/* ==========================================================================
   MATCH ME - DESIGN SYSTEM
   MOVEMENT: Floodlit Court

   The last system stood on a white page at midday. This one is the game after
   dark. Black is the ground the whole site is played on, not a theme that got
   switched. Lime is light, and on a black court light is scarce: one CTA, one
   active mark, one word in a headline, one glow. Gold is the metal you win, so
   it shows up on prizes, trophies and champions and nowhere a user clicks.

   Depth is made of surface lightness and a hairline, never a black shadow.
   Nothing on a black ground can cast a darker shadow and be believed.

   Palette is fixed by the brand book (BI.pdf), Color System page:
     Lime   #E8FC2C  primary
     Gold   #F3CA18  secondary, prizes only
     Black  #020202  the ground
     White  #FFFFFF  headings

   See BRAND.md for the full contract.
   ========================================================================== */

:root{
  /* -- brand primitives, verbatim from the book ------------------------- */
  --lime:#E8FC2C; --gold:#F3CA18; --black:#020202; --white:#FFFFFF;

  /* Tints of the two brand colours. Lime is so light that anything sitting
     ON it takes the ground colour, never white. */
  --lime-hi:#F2FF5E; --lime-dim:#B9CC1F; --lime-ink:#0C0F00;
  --gold-hi:#FFDA3D; --gold-dim:#B8981A; --gold-ink:#140F00;

  /* -- surfaces. The deck builds depth by layering near-black shapes over
     black, so the ramp is tight and stays in the same family. ----------- */
  --bg:#020202; --surface:#090909; --card:#111113; --card-2:#17171A;
  --card-3:#1E1E22; --line:#232327; --line-2:#2E2E34;
  /* --line and --line-2 are decorative hairlines: they separate surfaces that
     have already separated themselves by lightness, so they are allowed to sit
     below 3:1. The boundary of an interactive control is not decoration — it is
     the only thing saying "this is a control" — so controls take --line-ctl,
     which clears 3:1 on every surface in the ramp (WCAG 1.4.11, BRAND law 5). */
  --line-ctl:rgba(255,255,255,.36);

  /* -- text ramp. White stepping down in opacity, never a coloured grey.
     .52 is the floor for anything that must be read: 4.6:1 on #020202. -- */
  --tx:#FFFFFF;
  --tx-2:rgba(255,255,255,.72);
  --tx-3:rgba(255,255,255,.52);
  --tx-4:rgba(255,255,255,.34);

  /* -- state. Not brand colours; they only encode state, and they are the
     dark-surface tuned versions of each hue. ---------------------------- */
  --ok:#3FD06A; --ok-bg:rgba(63,208,106,.12); --ok-line:rgba(63,208,106,.32);
  --ok-ink:#04200D;
  --danger:#FF5A5F; --danger-bg:rgba(255,90,95,.12); --danger-line:rgba(255,90,95,.34);
  /* White on #FF5A5F is only 3.05:1, under the 4.5 floor for a button label or
     a toast. Every other fill in this system takes a dark ink; danger does too,
     at 6.5:1. */
  --danger-ink:#1A0203;
  --info:#8A7BD8; --info-bg:rgba(138,123,216,.14); --info-line:rgba(138,123,216,.34);
  /* --info is the fill; white on it is only 3.6:1, so fills take dark ink
     and text on a tint takes the lighter --info-tx (8.4:1 on the ground). */
  --info-tx:#A99BE8; --info-ink:#0B0716;
  /* Caution. Distinct from the prize gold in hue so a warning never reads as
     something won, and warm enough not to be mistaken for the lime primary. */
  --warn:#FFA733; --warn-bg:rgba(255,167,51,.13); --warn-line:rgba(255,167,51,.36);
  --lime-bg:rgba(232,252,44,.11); --lime-line:rgba(232,252,44,.34);
  --gold-bg:rgba(243,202,24,.11); --gold-line:rgba(243,202,24,.34);

  /* Legacy aliases. Older markup still says var(--navy) / var(--g500); every
     one of them now resolves into the dark system instead of a light one. */
  --navy:var(--card); --navy-2:var(--card-2); --navy-3:var(--card-2); --navy-4:var(--card-3);
  --ink:var(--tx); --off:var(--surface);
  --g700:var(--tx-2); --g500:var(--tx-3); --g300:var(--line-2); --g200:var(--line); --g100:var(--card-2);
  --green:var(--ok); --green-ink:var(--ok); --green-bg:var(--ok-bg);
  --purple:var(--info); --purple-ink:var(--info); --purple-bg:var(--info-bg);
  --red:var(--danger); --red-ink:var(--danger); --red-bg:var(--danger-bg);
  --gold-light:var(--gold-bg); --gold-deep:var(--gold);

  /* -- ONE radius system ------------------------------------------------
     pill  : buttons, chips, status pills
     card  : cards, media frames, panels
     field : inputs and small controls
     round : avatars and icon circles only                                  */
  --r-pill:999px; --r-card:20px; --r-field:12px; --r-round:50%;
  --r-sm:var(--r-field); --r-md:var(--r-card); --r-lg:var(--r-card);

  /* -- type scale. Arabic needs more x-height than Latin at the same
     optical size, so the display step is gentler than a Latin ratio. ----- */
  --t-display:clamp(2.6rem,6.4vw,5.1rem);
  --t-h1:clamp(2.1rem,4.4vw,3.4rem);
  --t-h2:clamp(1.7rem,3vw,2.5rem);
  --t-h3:clamp(1.1rem,1.5vw,1.35rem);
  --t-body:clamp(1rem,.97rem + .15vw,1.06rem);
  --t-lead:clamp(1.02rem,1.2vw,1.14rem);
  /* Three small steps, and 13px is the floor. There were eleven distinct
     values living between .72rem and .94rem — eleven steps inside a range of
     2.1px, which is a difference nobody can see and every one of which had to
     be maintained. `--t-micro:.72rem` was declared here and referenced
     nowhere: the 11.52px it names was hardcoded seven times instead. */
  --t-xs:.8125rem;   /* 13 — chips, tags, eyebrows. Nothing goes under this. */
  --t-sm:.875rem;    /* 14 — field labels, table cells, meta rows */
  --t-md:.9375rem;   /* 15 — secondary body, buttons, tab labels */
  /* Not a preference: under 16px iOS Safari zooms the viewport on focus and
     never zooms back. */
  --t-control:1rem;

  /* -- elevation. On black a drop shadow is invisible, so lift is carried
     by the surface step and the hairline. Shadows exist only as glow. ---- */
  /* These were black blurs. On #020202 a black blur has nothing to darken, so
     it rendered as nothing at all and only cost a paint. Lift is a hairline
     ring now — the same thing the eye actually reads on a dark ground — and
     the raised surface underneath does the rest of the work. */
  --shadow-sm:0 1px 0 rgba(255,255,255,.03) inset;
  --shadow-md:0 0 0 1px rgba(255,255,255,.07);
  --shadow-lg:0 0 0 1px rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.05) inset;
  --glow-lime:0 12px 34px -12px rgba(232,252,44,.42);
  --glow-lime-lg:0 18px 54px -14px rgba(232,252,44,.5);
  --glow-gold:0 12px 30px -12px rgba(243,202,24,.4);

  /* -- motion ----------------------------------------------------------- */
  --ease:cubic-bezier(.16,1,.3,1);
  --ease-soft:cubic-bezier(.32,.72,0,1);
  --ease-rebound:cubic-bezier(.34,1.28,.64,1);
  --dur-micro:220ms; --dur-ui:380ms; --dur-enter:720ms;

  --wrap:1280px;
  --gutter:28px;
  --bleed:max(var(--gutter),calc((100vw - var(--wrap)) / 2 + var(--gutter)));
  --nav-h:76px;
  --tap:44px;

  color-scheme:dark;
}

*,*::before,*::after{margin:0;padding:0;box-sizing:border-box;}
html{scroll-behavior:smooth;overflow-x:clip;background:var(--bg);
  /* Clears the fixed header (76px tall, offset 14px from the top). Without
     this, a field reached by the keyboard's Next button, or any in-page
     anchor, comes to rest behind it and the visitor types blind. */
  scroll-padding-top:104px;}
body{
  font-family:'Cairo',system-ui,sans-serif;
  background:var(--bg); color:var(--tx-2);
  font-size:var(--t-body);
  line-height:1.75; overflow-x:clip;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
}
img,svg{max-width:100%;display:block;}
a{text-decoration:none;color:inherit;}
ul,ol{list-style:none;}
button{font-family:inherit;cursor:pointer;border:none;background:none;color:inherit;}
input,select,textarea{font-family:inherit;font-size:1rem;color:inherit;}
::selection{background:var(--lime);color:var(--lime-ink);}

a[class*="btn"],button,.icon-btn,.nav-cta,.store-btn,.filter-chips button{min-height:var(--tap);}
/* The focus ring is lime because lime is the brightest thing on the page and
   a keyboard user should never have to hunt for where they are. */
:focus-visible{outline:2.5px solid var(--lime);outline-offset:3px;border-radius:var(--r-field);}

.container{max-width:var(--wrap);margin-inline:auto;padding-inline:var(--gutter);}
/* Fluid rather than stepped. These three values were the whole content of a
   `max-width:900px` query — a breakpoint that existed only to make spacing
   smaller, and which snapped 44px of section padding away in a single pixel.
   The ramps land on the old numbers at both ends and interpolate between. */
.section{padding-block:clamp(68px,11.8vw,112px);position:relative;}
.section--tight{padding-block:clamp(48px,8vw,76px);}
:root{--gutter:clamp(20px,2.95vw,28px);}

/* The page theme is locked. `.dark` and `.off` are legacy modifiers kept so
   existing markup keeps working; both now resolve to bands inside the same
   black family instead of flipping the page to a light ground. */
.dark{background:var(--surface);color:var(--tx-2);}
.off{background:var(--surface);}
/* Two raised bands in a row would merge into one oversized slab, so the
   second one drops back to the ground and the rhythm survives. */
.section.off + .section.off,
.off + .off,
.dark + .dark{background:var(--bg);}

/* ---------- Brand grounds ----------
   The deck's three recurring devices, as reusable section grounds. */

/* Chevron ground: wide diagonals cut from the background one step lighter
   than it, exactly as the brand board layers them. */
.dotfield{position:relative;isolation:isolate;}
.dotfield::before{
  content:"";position:absolute;inset:0;pointer-events:none;z-index:-1;
  background:
    linear-gradient(115deg,transparent 18%,#0A0A0C 18%,#0A0A0C 34%,transparent 34%),
    linear-gradient(-115deg,transparent 52%,#08080A 52%,#08080A 71%,transparent 71%);
  opacity:.9;
}
.dotfield > *{position:relative;z-index:1;}

/* Lime spark field: the deck's drifting particles, clustered to one corner
   and fading out. Decorative only, never behind body copy. */
.glow-field{position:absolute;inset:0;pointer-events:none;overflow:hidden;z-index:0;}
.glow-field::before{content:"";position:absolute;inset:0;
  background-image:radial-gradient(var(--lime) 1px,transparent 1.6px);
  background-size:26px 26px;
  -webkit-mask-image:radial-gradient(ellipse 60% 70% at 8% 88%,#000 0%,transparent 70%);
  mask-image:radial-gradient(ellipse 60% 70% at 8% 88%,#000 0%,transparent 70%);
  opacity:.5;}
/* The live field from spark-field.js. It replaces the flat pattern above
   rather than sitting on top of it, so a page without JS keeps the static
   sparks and a page with JS gets the moving ones — never both. */
.glow-field.has-spark::before{display:none;}
.spark-canvas{position:absolute;inset:0;width:100%;height:100%;
  pointer-events:none;display:block;}
/* A positioned element paints above non-positioned content in the same
   stacking context, so a decorative layer would land on top of the very copy
   it is meant to sit behind. Every sibling that follows one is lifted onto
   its own layer above it. */
.glow-field ~ *{position:relative;z-index:1;}
/* The hero is the exception: its art is a sibling too, and the sparks belong
   between the picture and the copy, continuing the ones baked into the
   render rather than hiding behind it. */
.hero-shot > .glow-field{z-index:1;}
.hero-shot > .hero-shot__bg{z-index:0;}
/* The same soft glow as a 90px blur filter on a solid disc, drawn as a
   radial gradient instead. A blur that wide is one of the costliest things a
   browser can rasterize; a gradient is painted once. Scaled so its soft edge
   reaches as far as the blurred disc's did. */
.glow-blob{position:absolute;border-radius:var(--r-round);opacity:.14;pointer-events:none;
  background:radial-gradient(closest-side,var(--blob,var(--lime)) 30%,transparent);
  transform:scale(1.85);}
.glow-blob.gold{--blob:var(--lime);}
.glow-blob.blue{--blob:var(--info);opacity:.1;}

/* Diagonal lime stripes, the deck's pattern swatch. One accent band only. */
.diag-strip{position:absolute;width:220px;height:100%;top:0;
  background:repeating-linear-gradient(115deg,var(--lime) 0 6px,transparent 6px 16px);
  opacity:.07;pointer-events:none;}

/* ---------- Typography ---------- */
/* One blanket weight for every heading element meant 14 unclassed <h1>s on the
   site were set at Bold where the book sets H1 in Black. The elements now match
   the book's own ladder: H1 Black 900, H2 Bold, H3/H4 SemiBold-to-Bold. */
h1,h2,h3,h4{line-height:1.18;text-wrap:balance;color:var(--tx);}
h1{font-weight:900;}
h2{font-weight:800;}
h3,h4{font-weight:800;}
.h0{font-size:var(--t-display);font-weight:900;letter-spacing:-.02em;line-height:1.06;color:var(--tx);}
.h1{font-size:var(--t-h1);font-weight:900;letter-spacing:-.016em;line-height:1.12;color:var(--tx);}
/* The book sets H2 in Cairo Bold and BRAND.md fixes the range at 700-800. This
   was 900, one step heavier than the contract allows, which flattened the step
   between an H1 and the H2 under it. */
.h2{font-size:var(--t-h2);font-weight:800;letter-spacing:-.012em;line-height:1.18;color:var(--tx);}
.h3{font-size:var(--t-h3);font-weight:800;letter-spacing:-.004em;color:var(--tx);}
.lead{font-size:var(--t-lead);color:var(--tx-2);font-weight:500;line-height:1.85;max-width:60ch;}
.dark .lead{color:var(--tx-2);}
/* `.gold` is the class the markup uses for the one highlighted word in a
   headline. On this identity that word is lime: it is the primary, and a
   highlighted word is emphasis, not a prize. */
.gold,.text-gold,.dark .gold,.dark .text-gold{color:var(--lime);}
.latin{font-feature-settings:"ss01";letter-spacing:-.01em;}

/* Eyebrow. Lime, tight, one per section head at most. */
.eyebrow{display:inline-flex;align-items:center;gap:9px;
  font-size:var(--t-xs);font-weight:800;letter-spacing:.1em;color:var(--lime);}
.dark .eyebrow,.panel-dark .eyebrow,
.prize-hero .eyebrow,.feature-card--lead .eyebrow{color:var(--lime);}
.eyebrow::before{content:"";width:16px;height:2px;border-radius:2px;background:currentColor;opacity:.6;}
.section-head{margin-bottom:44px;max-width:56ch;}
.section-head .h2{margin-top:14px;}
.section-head .lead{margin-top:16px;}
.section-head.center{margin-inline:auto;text-align:center;}
.section-head.center .eyebrow{justify-content:center;}

/* ---------- Buttons ----------
   Exactly one lime button per view. Gold is never a button: gold means a
   prize was won, and a thing you click to proceed has not won anything.
   A trailing arrow always rides in its own circle so it never floats naked
   beside the label. */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:12px;
  padding:15px 22px;border-radius:var(--r-pill);
  font-weight:800;font-size:var(--t-md);line-height:1;white-space:nowrap;
  transition:transform var(--dur-micro) var(--ease-soft),
             background var(--dur-micro) linear,
             color var(--dur-micro) linear,
             border-color var(--dur-micro) linear,
             box-shadow var(--dur-ui) var(--ease-soft);}
.btn:not(:has(.btn-icon)){padding-inline:28px;}

/* .btn-gold is the markup's name for the primary action. It is lime now. */
.btn-gold{background:var(--lime);color:var(--lime-ink);box-shadow:var(--glow-lime);}
@media(hover:hover){
  .btn-gold:hover{background:var(--lime-hi);transform:translateY(-2px);box-shadow:var(--glow-lime-lg);}
}
.btn-dark{background:var(--card-2);color:var(--tx);border:1.5px solid var(--line-ctl);}
@media(hover:hover){
  .btn-dark:hover{background:var(--card-3);border-color:var(--lime);color:var(--lime);transform:translateY(-2px);}
}
.btn-outline{background:rgba(255,255,255,.05);border:1.5px solid var(--line-ctl);color:var(--tx);}
@media(hover:hover){
  .btn-outline:hover{border-color:var(--lime);color:var(--lime);background:var(--lime-bg);}
}
/* Named "dark" because on the old white page it was the dark option. On this
   ground the quiet option is the outlined one. */
.btn-outline-dark{background:transparent;border:1.5px solid var(--line-ctl);color:var(--tx);}
@media(hover:hover){
  .btn-outline-dark:hover{border-color:var(--lime);background:var(--lime-bg);color:var(--lime);}
}
.btn-green{background:var(--ok);color:var(--ok-ink);}
@media(hover:hover){
  .btn-green:hover{filter:brightness(1.08);transform:translateY(-2px);}
}
.btn-red{background:var(--danger-bg);color:var(--danger);border:1.5px solid var(--danger-line);}
@media(hover:hover){
  .btn-red:hover{background:var(--danger);color:var(--danger-ink);border-color:var(--danger);}
}
/* The press. This has to outrank the variants' own :hover transforms, because
   a press always happens while hovering: at equal specificity the later
   @media(hover:hover){
     `.btn-gold:hover{transform:translateY(-2px)}` simply won and the button gave
   }
   no feedback at all when it was pushed. */
.btn:active,.btn:active:hover{transform:scale(.975);}
.btn-block,.w-full{width:100%;}
.btn-lg{padding:19px 24px;font-size:1rem;}
.btn-lg:not(:has(.btn-icon)){padding-inline:34px;}
.btn-sm{padding:10px 18px;font-size:var(--t-sm);min-height:var(--tap);}
.btn[disabled],.btn.is-disabled{opacity:.5;cursor:not-allowed;transform:none!important;box-shadow:none;pointer-events:none;}
/* Loading state: the label stays put and the icon circle spins, so the
   button does not change width mid-request. */
.btn.is-loading{pointer-events:none;position:relative;color:transparent;}
.btn.is-loading::after{content:"";position:absolute;width:18px;height:18px;border-radius:var(--r-round);
  border:2px solid currentColor;border-top-color:transparent;color:var(--lime-ink);
  animation:spin .7s linear infinite;}
.btn-outline.is-loading::after,.btn-outline-dark.is-loading::after,.btn-dark.is-loading::after{color:var(--lime);}
@keyframes spin{to{transform:rotate(360deg);}}

.btn-icon{width:28px;height:28px;border-radius:var(--r-round);
  display:flex;align-items:center;justify-content:center;flex-shrink:0;
  background:rgba(255,255,255,.14);transition:transform var(--dur-micro) var(--ease-soft);}
.btn-gold .btn-icon,.btn-green .btn-icon{background:rgba(2,2,2,.16);}
.btn-dark .btn-icon,.btn-outline .btn-icon,.btn-outline-dark .btn-icon{background:rgba(255,255,255,.12);}
@media(hover:hover){
  .btn:hover .btn-icon{transform:translateX(-4px);}
}
@media(hover:hover){
  [dir=ltr] .btn:hover .btn-icon{transform:translateX(4px);}
}

/* The official Apple and Google badges, used as artwork. Both are set to the
   same height; Google's is the wider of the two by design. The Apple badge
   ships as black-on-white artwork, so on this ground it takes a light plate
   rather than being inverted, which would break the trademark. */
.store-badges{display:flex;align-items:center;gap:12px;flex-wrap:wrap;}
.store-badges a{display:block;border-radius:9px;
  transition:transform var(--dur-micro) var(--ease-soft),box-shadow var(--dur-ui) var(--ease-soft);}
@media(hover:hover){
  .store-badges a:hover{transform:translateY(-3px);box-shadow:var(--shadow-md);}
}
.store-badges img{height:50px;width:auto;display:block;}
.store-badges--lg img{height:56px;}
@media(max-width:560px){.store-badges img{height:44px;}}

/* ---------- Icons ---------- */
.ic{width:18px;height:18px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round;}
.ic-sm{width:15px;height:15px;}
/* Official platform marks are solid glyphs, so they opt out of the outline
   treatment the rest of the icon set uses. */
.ic-brand{fill:currentColor;stroke:none;}
.ic-lg{width:26px;height:26px;}

/* Every page opens with the same header and the same nav. Without this, a
   keyboard or screen-reader visitor tabs through all of it again on every
   page before reaching anything the page is actually about. It is off-screen
   until focused, which is the only state in which it is any use. */
.skip-link{position:absolute;inset-inline-start:16px;top:-100px;z-index:600;
  background:var(--lime);color:var(--lime-ink);font-weight:800;font-size:var(--t-sm);
  padding:12px 20px;border-radius:var(--r-pill);min-height:var(--tap);
  display:inline-flex;align-items:center;text-decoration:none;
  transition:top var(--dur-ui) var(--ease-soft);}
.skip-link:focus-visible{top:calc(14px + env(safe-area-inset-top,0px));}

/* ==========================================================================
   HEADER - a black capsule, logo at the start, links centred, actions at end
   ========================================================================== */
/* A notched phone reserves a strip at the top that the page is allowed to
   paint into but must not put anything readable in. Fourteen pixels from the
   top of the viewport is fourteen pixels into the status bar. */
.site-header{position:fixed;top:calc(14px + env(safe-area-inset-top,0px));
  left:0;right:0;z-index:200;}
.nav-pill{max-width:1400px;margin-inline:auto;padding-inline:clamp(14px,2vw,28px);}
.nav-inner{display:flex;align-items:center;gap:20px;
  height:var(--nav-h);padding-inline:clamp(16px,2.4vw,30px);
  border-radius:var(--r-pill);
  /* A backdrop blur on a fixed element is recomputed on every scroll frame,
     over whatever happens to be behind it. The saturate pass doubled that for
     a difference nobody could name, and on a phone the blur itself goes: the
     capsule is near-opaque there and the page behind it is black anyway. */
  background:rgba(9,9,9,.78);backdrop-filter:blur(12px);
  border:1px solid rgba(255,255,255,.1);
  box-shadow:var(--shadow-md);
  transition:box-shadow var(--dur-ui) var(--ease-soft),background var(--dur-ui) linear,
             border-color var(--dur-ui) linear;}
/* Once the page has moved off the top the capsule firms up, so nav text keeps
   its contrast over whatever is scrolling behind it. */
.nav-inner.is-stuck{background:rgba(2,2,2,.94);border-color:rgba(255,255,255,.14);
  box-shadow:var(--shadow-lg);}

/* One traced lockup. Lime is the default per the Logo Versions page; the
   white variant is used only where lime would collide with adjacent lime. */
.logo{display:inline-flex;align-items:center;flex-shrink:0;
  min-height:var(--tap);color:var(--lime);}
.logo .logo-svg{width:104px;height:auto;}
.mobile-panel .logo{color:var(--lime);}
.site-footer .logo .logo-svg{width:132px;}
@media(max-width:560px){.logo .logo-svg{width:88px;}}

.nav-links{display:flex;align-items:center;gap:clamp(10px,1.7vw,26px);margin-inline:auto;}
.nav-links a{position:relative;display:inline-flex;align-items:center;min-height:var(--tap);
  font-size:var(--t-sm);font-weight:700;color:var(--tx-2);white-space:nowrap;
  transition:color var(--dur-micro) linear;}
@media(hover:hover){
  .nav-links a:hover{color:var(--tx);}
}
.nav-links a.active{color:var(--tx);}
.nav-links a:active{opacity:.7;}
.nav-links a.active::after{content:"";position:absolute;bottom:4px;inset-inline:0;height:3px;
  background:var(--lime);border-radius:3px;}

@media(pointer:coarse){
  .nav-inner{backdrop-filter:none;background:rgba(9,9,9,.93);}
}
.nav-actions{display:flex;align-items:center;gap:10px;flex-shrink:0;}
.lang-switch{display:flex;align-items:center;gap:6px;font-size:var(--t-xs);font-weight:700;
  color:var(--tx-3);padding-inline:4px;white-space:nowrap;}
.lang-switch a{color:var(--tx-3);display:inline-flex;align-items:center;min-height:var(--tap);
  transition:color var(--dur-micro) linear;}
.lang-switch a b{color:inherit;font-weight:700;}
@media(hover:hover){
  .lang-switch a:hover b{color:var(--tx);}
}
.lang-switch a.is-active b{color:var(--lime);}
.lang-switch a.is-active{pointer-events:none;}

.nav-cta{background:transparent;color:var(--lime);border:1.5px solid var(--lime);
  font-weight:800;font-size:var(--t-sm);
  padding:12px 22px;border-radius:var(--r-pill);white-space:nowrap;display:inline-flex;
  align-items:center;
  transition:transform var(--dur-micro) var(--ease-soft),background var(--dur-micro) linear,
             color var(--dur-micro) linear,box-shadow var(--dur-ui) var(--ease-soft);}
@media(hover:hover){
  .nav-cta:hover{transform:translateY(-2px);background:var(--lime);color:var(--lime-ink);
    box-shadow:var(--glow-lime);}
}
.nav-cta:active,.nav-cta:active:hover{transform:scale(.975);}
.nav-dl{width:44px;height:44px;border-radius:var(--r-round);background:rgba(255,255,255,.07);
  border:1.5px solid var(--line-ctl);color:var(--tx);display:flex;align-items:center;justify-content:center;
  transition:background var(--dur-micro) linear,color var(--dur-micro) linear,border-color var(--dur-micro) linear;}
@media(hover:hover){
  .nav-dl:hover{background:var(--lime);border-color:var(--lime);color:var(--lime-ink);}
}
.nav-dl:active{transform:scale(.92);}

.burger{display:none;width:44px;height:44px;border-radius:var(--r-round);
  background:rgba(255,255,255,.07);border:1.5px solid var(--line-ctl);
  align-items:center;justify-content:center;flex-direction:column;gap:5px;}
.burger span{width:16px;height:2px;background:var(--tx);border-radius:2px;
  transition:transform .35s var(--ease-soft),opacity .2s;}
.burger.open span:nth-child(1){transform:translateY(7px) rotate(45deg);}
.burger.open span:nth-child(2){opacity:0;}
.burger.open span:nth-child(3){transform:translateY(-7px) rotate(-45deg);}

/* The mobile menu is a sheet, not a poster. It was thirteen centred rows at
   21.6px/800 — the weight of a section heading — which needed 1,074px on an
   812px screen, so it scrolled before showing half of itself and read as a
   wall of shouting. It is now a top-aligned two-column grid of compact tiles
   under the header, with the one action and the language switch pinned to
   the bottom where a thumb already is. */
.mobile-panel{position:fixed;inset:0;background:rgba(2,2,2,.97);
  z-index:190;display:flex;flex-direction:column;
  /* The panel covers the whole viewport, so its own padding is what keeps the
     grid clear of the header capsule and the foot clear of the home
     indicator. */
  padding:calc(var(--nav-h) + 32px + env(safe-area-inset-top,0px)) 20px
          calc(20px + env(safe-area-inset-bottom,0px));
  opacity:0;pointer-events:none;overflow-y:auto;overscroll-behavior:contain;
  /* Closed, the panel must leave the tab order too. `visibility` is
     animatable in discrete steps, so it holds through the fade out and then
     takes its links off the keyboard path. */
  visibility:hidden;
  transition:opacity .3s var(--ease),visibility 0s linear .3s;}
.mobile-panel.open{opacity:1;pointer-events:auto;visibility:visible;
  transition:opacity .3s var(--ease),visibility 0s linear 0s;}

.mp-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;
  width:100%;max-width:520px;margin-inline:auto;}
.mp-grid a{display:flex;align-items:center;min-height:52px;padding:8px 14px;
  border-radius:var(--r-field);background:rgba(255,255,255,.035);
  border:1px solid rgba(255,255,255,.08);
  font-size:var(--t-md);font-weight:700;line-height:1.35;color:var(--tx-2);
  opacity:0;transform:translateY(8px);
  transition:opacity .35s var(--ease),transform .35s var(--ease),
             background var(--dur-micro) linear,border-color var(--dur-micro) linear,color var(--dur-micro) linear;
  transition-delay:calc(var(--i,0) * 16ms),calc(var(--i,0) * 16ms),0s,0s,0s;}
/* Thirteen tiles in two columns leave a hole beside the last one. An odd
   last tile takes the whole row instead, so the grid ends square. */
.mp-grid a:last-child:nth-child(odd){grid-column:1 / -1;}
.mp-grid a:active{background:rgba(255,255,255,.08);color:var(--tx);}
@media(hover:hover){
  .mp-grid a:hover{border-color:rgba(255,255,255,.2);color:var(--tx);}
}
/* The page you are on, said once, in the brand colour. */
.mp-grid a[aria-current="page"]{color:var(--lime);border-color:rgba(232,252,44,.4);
  background:rgba(232,252,44,.06);}
.mobile-panel.open .mp-grid a{opacity:1;transform:none;}

/* `margin-top:auto` pins the foot to the bottom while there is room, and
   resolves to zero when there is not, so it never overlaps the grid. */
.mp-foot{margin-top:auto;padding-top:24px;display:flex;flex-direction:column;gap:10px;
  width:100%;max-width:520px;margin-inline:auto;}
.mp-foot > *{opacity:0;transform:translateY(8px);
  transition:opacity .35s var(--ease) .2s,transform .35s var(--ease) .2s;}
.mobile-panel.open .mp-foot > *{opacity:1;transform:none;}
.mp-foot .btn{width:100%;}
.mobile-panel .btn{color:var(--lime-ink);}
.mobile-panel .btn-outline-dark,.mobile-panel .btn-outline{color:var(--tx);}
.mobile-lang{display:flex;justify-content:center;}
.mobile-panel .lang-switch{color:var(--tx-4);}
@media(hover:hover){
  .mobile-panel .lang-switch a:hover b{color:var(--tx);}
}
.mobile-panel .lang-switch a.is-active b{color:var(--lime);}

@media(max-width:1180px){
  .nav-links{display:none;}
  /* On desktop the links' own `margin-inline:auto` is what pushes the
     actions to the far end of the capsule. With the links hidden nothing
     did, so the burger and download buttons sat 20px from the logo and left
     the other half of the capsule empty. */
  .nav-actions{margin-inline-start:auto;}
  .burger{display:flex;}
  /* Scoped to the header capsule. Unscoped, this also hid the copy inside the
     mobile panel — which ui.js renders precisely so the language can be
     changed on a phone — leaving no way to reach the English site at all. */
  .nav-inner .lang-switch{display:none;}
}
@media(max-width:560px){
  .nav-cta{display:none;}
  .logo .word i{display:none;}
}
.header-spacer{height:calc(var(--nav-h) + 14px);}

/* ==========================================================================
   FOOTER - the ground the page was standing on all along
   ========================================================================== */
/* The WhatsApp button floats 22px from the bottom and is 58px across, so the
   foot of every page reserves room for it rather than letting it come to rest
   on top of whatever ends the page. */
@media(max-width:768px){
  .site-footer{padding-bottom:calc(92px + env(safe-area-inset-bottom,0px));}
}
.site-footer{background:var(--surface);color:var(--tx-3);position:relative;overflow:hidden;
  border-top:1px solid var(--line);}
.footer-top{padding-block:76px 46px;position:relative;z-index:2;}
.footer-grid{display:grid;grid-template-columns:1.5fr 1fr 1fr 1fr 1.3fr;gap:38px;}
.footer-brand .logo{margin-bottom:16px;}
/* These are <h2> and look exactly as they did as <h4>. They were <h4> with
   nothing between them and the page's own <h2>, so the outline of every page
   on the site ended H2 -> H4 H4 H4 H4 — four headings at a depth that has no
   parent. Heading level is document structure, not size. */
.footer-col .footer-h{color:var(--tx);font-size:var(--t-md);font-weight:800;
  line-height:1.4;margin-bottom:18px;letter-spacing:.02em;}
.footer-col ul{display:flex;flex-direction:column;gap:2px;}
/* Contact rows: icon, then the number or address kept left-to-right. */
.footer-contact a{gap:10px;color:var(--tx-2);}
.footer-contact .ic{flex-shrink:0;color:var(--lime);}
.footer-contact span{overflow-wrap:anywhere;font-variant-numeric:tabular-nums;}
.footer-reach .footer-apps{margin-top:26px;}
.footer-reach .footer-contact + .footer-apps{padding-top:22px;border-top:1px solid var(--line);}
.footer-col .store-badges{flex-direction:column;align-items:flex-start;gap:10px;}
.footer-col .store-badges img{height:44px;}
.footer-col a{font-size:var(--t-sm);transition:color var(--dur-micro) linear;}
@media(hover:hover){
  .footer-col a:hover{color:var(--lime);}
}
.footer-social{display:flex;flex-wrap:wrap;gap:10px;margin-top:18px;max-width:320px;}
.footer-social a{width:40px;height:40px;border-radius:var(--r-round);
  border:1px solid var(--line-2);display:flex;align-items:center;justify-content:center;
  transition:background var(--dur-micro) linear,color var(--dur-micro) linear,
             border-color var(--dur-micro) linear,transform var(--dur-micro) var(--ease-soft);}
@media(hover:hover){
  .footer-social a:hover{background:var(--lime);color:var(--lime-ink);border-color:var(--lime);transform:translateY(-3px);}
}
.footer-social a:active{transform:translateY(-1px) scale(.94);}
.footer-bottom{border-top:1px solid var(--line);padding-block:24px;
  display:flex;justify-content:center;align-items:center;gap:10px 26px;flex-wrap:wrap;
  font-size:var(--t-sm);position:relative;z-index:2;text-align:center;}
.footer-legal{display:flex;align-items:center;gap:8px 20px;flex-wrap:wrap;justify-content:center;}
.footer-legal a{color:var(--tx-2);text-decoration:underline;text-underline-offset:3px;text-decoration-color:var(--line-2);}
@media(hover:hover){.footer-legal a:hover{color:var(--lime);text-decoration-color:currentColor;}}

/* Newsletter: input and its send button read as one control. */
.subscribe{display:flex;align-items:center;gap:8px;background:var(--card);
  border:1px solid var(--line-ctl);border-radius:var(--r-pill);padding:6px;
  max-width:320px;transition:border-color var(--dur-micro) linear;}
.subscribe:focus-within{border-color:var(--lime);}
.subscribe input{flex:1;min-width:0;min-height:var(--tap);background:none;border:none;color:var(--tx);
  padding-inline:16px;font-size:var(--t-sm);font-weight:600;}
.subscribe input::placeholder{color:var(--tx-3);}
.subscribe input:focus:not(:focus-visible){outline:none;}
.subscribe button:active{transform:scale(.94);}
.subscribe button[disabled],.subscribe.is-loading button{opacity:.45;pointer-events:none;}
.subscribe.is-loading button::after{content:"";width:16px;height:16px;border-radius:var(--r-round);
  border:2px solid var(--lime-ink);border-top-color:transparent;animation:spin .7s linear infinite;}
.subscribe.is-loading button .ic{display:none;}
.subscribe button{width:44px;height:44px;flex-shrink:0;border-radius:var(--r-round);
  background:var(--lime);color:var(--lime-ink);display:flex;align-items:center;justify-content:center;
  transition:transform var(--dur-micro) var(--ease-soft),background var(--dur-micro) linear;}
@media(hover:hover){
  .subscribe button:hover{background:var(--lime-hi);transform:scale(1.06);}
}

@media(max-width:1024px){.footer-grid{grid-template-columns:1.4fr 1fr 1fr;gap:34px;}
  .footer-brand{grid-column:1/-1;} }
@media(max-width:768px){.footer-grid{grid-template-columns:1fr 1fr;} }
/* The accordion toggle reads as a plain heading on anything wider than a phone. */
.footer-acc{all:unset;display:flex;align-items:center;justify-content:space-between;gap:10px;
  width:100%;cursor:default;font:inherit;color:inherit;}
.footer-chev{display:none;transition:transform var(--dur-micro) var(--ease-soft);}

/* Phone: centered brand, collapsible link groups, badges side by side. */
@media(max-width:560px){
  .footer-top{padding-block:44px 8px;}
  .footer-grid{grid-template-columns:1fr;gap:0;}
  .footer-brand{text-align:center;display:flex;flex-direction:column;align-items:center;
    padding-bottom:26px;margin-bottom:6px;border-bottom:1px solid var(--line);}
  .footer-brand .logo{margin-bottom:12px;}
  .footer-brand p{margin-inline:auto;}
  .footer-social{justify-content:center;margin-top:14px;margin-inline:auto;}

  .footer-col{border-bottom:1px solid var(--line);}
  .footer-col .footer-h{margin:0;font-size:1rem;}
  .footer-acc{cursor:pointer;min-height:56px;-webkit-tap-highlight-color:transparent;}
  .footer-acc:focus-visible{outline:2px solid var(--lime);outline-offset:-2px;border-radius:8px;}
  .footer-chev{display:block;color:var(--tx-3);}
  .footer-col.is-open .footer-chev{transform:rotate(180deg);color:var(--lime);}
  .footer-col.is-open .footer-acc{color:var(--lime);}
  .footer-col ul:not(.store-badges){display:none;}
  .footer-col.is-open ul:not(.store-badges){display:grid;grid-template-columns:1fr 1fr;
    gap:0 16px;padding-bottom:14px;}
  .footer-col.is-open ul a{min-height:42px;color:var(--tx-2);}

  /* Contacts and app badges are never collapsed on a phone: they are the
     column a visitor on a phone is most likely looking for. */
  .footer-reach{border-bottom:0;padding-top:24px;text-align:center;}
  .footer-reach .footer-h{margin-bottom:12px;}
  .footer-col.footer-reach ul.footer-contact{display:flex;flex-direction:column;align-items:center;gap:0;}
  .footer-contact a{min-height:44px;}
  .footer-reach .footer-apps{margin-top:18px;}
  .footer-reach .footer-contact + .footer-apps{padding-top:20px;}
  .footer-col .store-badges{flex-direction:row;justify-content:center;flex-wrap:wrap;margin-top:0;gap:10px;}
  .footer-col .store-badges img{height:40px;}

  .footer-bottom{flex-direction:column;gap:4px;padding-block:18px;font-size:.78rem;}
}

/* ==========================================================================
   HERO - the render is the ground, the copy stands on it
   ========================================================================== */
/* The section takes its height from the render, not the other way round: the
   art runs in flow at full width and its natural aspect, so it is never
   cropped on any screen, and it starts below the fixed header rather than
   under it. The copy is then laid over the picture. */
.hero-shot{position:relative;overflow:hidden;background:var(--bg);
  padding-top:calc(var(--nav-h) + 22px);}
.hero-shot__bg{position:relative;z-index:0;}
.hero-shot__bg img{display:block;width:100%;height:auto;}
/* The art is a dark scene now, so the copy no longer needs a white halo to
   survive on it. It gets a soft black scrim on the copy side instead, which
   guarantees the headline clears AA no matter how the render is cropped. */
/* The copy sits at the inline start of the row, so the scrim is heaviest on
   the right in Arabic and on the left in English. */
.hero-shot__bg::before{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(to right,transparent 34%,rgba(2,2,2,.78) 76%,rgba(2,2,2,.94) 100%);}
[dir=ltr] .hero-shot__bg::before{
  background:linear-gradient(to left,transparent 34%,rgba(2,2,2,.78) 76%,rgba(2,2,2,.94) 100%);}
/* Both the hero and the court render now ship a plate per reading direction,
   composed so the copy column stays clear. Nothing is mirrored in CSS any
   more — flipping a correct plate would put the subject back under the text. */
/* The copy sits over the art, clear of the header. */
.hero-shot .container{position:absolute;inset:calc(var(--nav-h) + 22px) 0 0 0;z-index:2;
  display:flex;align-items:center;
  padding-block:clamp(16px,2.4vw,40px) clamp(40px,7vw,110px);}
.hero-copy{max-width:34rem;}
/* The wordmark opens the hero in place of a badge - the brand says itself. */
.hero-wordmark{font-weight:900;font-size:clamp(.9rem,1.5vw,1.05rem);
  letter-spacing:.34em;color:var(--lime);}
.hero-cta{display:flex;flex-wrap:wrap;gap:12px;margin-top:26px;}
/* The pair is a single pixel too wide for a 375px phone, so it wraps ragged.
   Below that width each button takes the row it was going to take anyway. */
@media(max-width:560px){.hero-cta{flex-direction:column;align-items:stretch;}}
.hero-badge{display:inline-flex;align-items:center;gap:9px;background:var(--ok-bg);
  border:1px solid var(--ok-line);
  color:var(--ok);font-weight:800;font-size:var(--t-xs);padding:9px 18px;border-radius:var(--r-pill);}
.hero-badge::before{content:"";width:7px;height:7px;border-radius:var(--r-round);
  background:var(--ok);}
/* Arabic sets wider than Latin at the same optical size, so the hero display
   steps down from the global scale to hold the headline on two lines. */
.hero-copy .h0{margin-top:12px;letter-spacing:-.03em;font-size:clamp(1.85rem,3.3vw,2.95rem);color:var(--tx);}
.hero-copy .h0 em{font-style:normal;color:var(--lime);}
.hero-copy .lead{margin-top:16px;max-width:46ch;font-size:.98rem;color:var(--tx-2);}
.hero-copy .hero-body{margin-top:12px;max-width:46ch;font-size:var(--t-md);color:var(--tx-3);}
.hero-copy .store-badges{margin-top:26px;}
.hero-note{margin-top:20px;font-size:var(--t-sm);font-weight:700;color:var(--tx-3);}
/* Narrow screens stack instead: the art keeps the full width at the top and
   the copy runs underneath it. */
@media(max-width:1024px){
  .hero-shot{padding-bottom:52px;}
  /* The 2.6:1 frame is a 140px ribbon on a phone. Narrow screens get a taller
     window onto the same file instead, centred on the phone and racket. */
  .hero-shot__bg{aspect-ratio:4/3;}
  .hero-shot__bg img{height:100%;object-fit:cover;}
  [dir=rtl] .hero-shot__bg img{object-position:31% 58%;}
  [dir=ltr] .hero-shot__bg img{object-position:69% 58%;}
  /* Stacked, the scrim runs bottom-up into the copy instead of sideways. */
  .hero-shot__bg::before,[dir=ltr] .hero-shot__bg::before{
    background:linear-gradient(to bottom,transparent 45%,rgba(2,2,2,.85) 92%,var(--bg) 100%);}
  .hero-shot__bg::after{content:"";position:absolute;inset-inline:0;bottom:-1px;height:18%;z-index:1;
    background:linear-gradient(to bottom,rgba(2,2,2,0),var(--bg));}
  .hero-shot .container{position:static;display:block;padding-block:28px 0;}
  .hero-copy{max-width:none;}
  .hero-copy .lead{max-width:44ch;}
}

/* A <picture> exists to carry alternative sources, not to be a box. With
   `display:contents` it leaves the layout tree entirely, so the image it
   wraps stays the flex or grid item it always was and no positioning rule
   needs rewriting. Selectors are a different matter: `picture` is still the
   DOM parent, which is why `.split-media--bleed > img` became a descendant
   selector just above. */
picture{display:contents;}

/* ==========================================================================
   SPLIT - copy on one side, the product render on the other
   ========================================================================== */
/* A phone reads a stacked .split as: eyebrow, heading, paragraph, button.
   This page runs that shape six times. Ordering the media first breaks the
   repetition without inventing a second layout to maintain. Above the fold
   point the grid decides the order, so this only applies once stacked. */
@media(max-width:1024px){
  .split--media-first{display:flex;flex-direction:column;}
  .split--media-first > :last-child{order:-1;}
}

/* On a phone the homepage's long prose folds to its opening paragraph and a
   link to the page that carries the whole thing. It is 20.4 screens tall and
   vertical space is the only currency a phone has. `display:none` takes these
   out of the accessibility tree too, which is why the link that replaces them
   is visible rather than implied. */
.m-more{display:none;}
@media(max-width:768px){
  .m-fold{display:none;}
  .m-more{display:inline-flex;align-items:center;gap:8px;margin-top:16px;
    min-height:var(--tap);font-weight:800;font-size:var(--t-md);color:var(--lime);}
  .m-more .ic{flex-shrink:0;}
}
.split{display:grid;grid-template-columns:minmax(0,.92fr) minmax(0,1.08fr);
  gap:clamp(34px,5vw,72px);align-items:center;}
/* The render leads: it takes the column the reader starts from, so it sits on
   the right in Arabic and on the left in English, with the copy opposite it. */
.split--art{grid-template-columns:minmax(0,1.22fr) minmax(0,.78fr);
  gap:clamp(16px,2vw,34px);align-items:stretch;}
.split--art > .split-media{order:1;}
.split--art > :not(.split-media){order:2;}
@media(max-width:1024px){
  .split,.split--art{grid-template-columns:1fr;gap:44px;}
  .split-media--bleed,[dir=rtl] .split-media--bleed{display:block;
    margin-inline:calc(-1 * var(--gutter));}
  .split-media--bleed img{height:auto;object-fit:contain;}
}
.split-media{position:relative;}
.split-media img{width:100%;height:auto;border-radius:var(--r-card);}
/* The render carries its own ground, so a hard edge against the page would
   show as a rectangle. It runs past the container to the page edge and its
   outer border fades out instead. */
.split-media--bleed{margin-inline-start:calc(-1 * var(--bleed));display:flex;}
.split-media--bleed img{flex:1 1 auto;min-width:0;width:100%;align-self:stretch;
  height:auto;object-fit:cover;max-width:none;border-radius:0;
  -webkit-mask-image:linear-gradient(to right,transparent 0,#000 7%,#000 93%,transparent 100%),
                     linear-gradient(to bottom,transparent 0,#000 6%,#000 94%,transparent 100%);
  mask-image:linear-gradient(to right,transparent 0,#000 7%,#000 93%,transparent 100%),
             linear-gradient(to bottom,transparent 0,#000 6%,#000 94%,transparent 100%);
  -webkit-mask-composite:source-in;mask-composite:intersect;}

/* ==========================================================================
   SPONSOR RAIL - a track of logo cards with arrows either side, dots below
   ========================================================================== */
.rail{position:relative;display:flex;align-items:center;gap:16px;}
.rail-arrow{width:44px;height:44px;flex-shrink:0;border-radius:var(--r-round);
  border:1.5px solid var(--lime-line);color:var(--lime);background:var(--card);
  display:flex;align-items:center;justify-content:center;
  transition:background var(--dur-micro) linear,color var(--dur-micro) linear,
             border-color var(--dur-micro) linear;}
@media(hover:hover){
  .rail-arrow:hover{background:var(--lime);color:var(--lime-ink);border-color:var(--lime);}
}
.rail-arrow:active:not([disabled]){transform:scale(.92);}
.rail-arrow[disabled]{opacity:.4;cursor:default;}
/* --items is written by the rail script. Fewer logos than fit means they
   spread to fill the row instead of leaving a gap at the end. */
.rail-track{--cols:min(6,var(--items,6));flex:1;min-width:0;display:grid;grid-auto-flow:column;
  grid-auto-columns:calc((100% - (var(--cols) - 1) * 18px) / var(--cols));gap:18px;
  overflow-x:auto;scroll-snap-type:x mandatory;
  scrollbar-width:none;padding-block:4px;}
/* No `scroll-behavior:smooth` here on purpose. Declared in CSS it combines
   with scroll-snap to cancel programmatic scrolls in Chromium, which left the
   arrows dead; the rail script asks for smooth per call instead. */
.rail-track::-webkit-scrollbar{display:none;}
.rail-card{scroll-snap-align:start;display:flex;align-items:center;justify-content:center;
  min-height:112px;aspect-ratio:1 / 1;padding:18px;background:var(--card);border:1.5px solid var(--line);
  border-radius:var(--r-card);font-weight:900;font-size:1.02rem;letter-spacing:.03em;
  color:var(--tx-2);text-align:center;
  transition:border-color var(--dur-micro) linear,transform var(--dur-ui) var(--ease-soft),
             background var(--dur-ui) linear,color var(--dur-micro) linear;}
@media(hover:hover){
  .rail-card:hover{border-color:var(--lime);color:var(--tx);background:var(--card-2);transform:translateY(-4px);}
}
.rail-card.is-strategic{color:var(--info);border-color:var(--info-line);}
/* An uploaded logo replaces the wordmark and is contained, never cropped.
   Partner logos arrive as dark-on-white artwork, so on this ground they get
   their own light plate rather than being inverted. */
/* Scaled to its slot, up or down, and never stretched: a logo meets the slot
   on its longer side whatever size the file was uploaded at. `max-width` and
   `max-height` alone could only ever shrink one, so a small upload stayed
   small in the middle of the card. */
.rail-card{position:relative;}
/* The image takes the whole card, inset 8px, rather than a 72px band across
   its middle: in a ~140px card that band left the picture at half the height
   it could have had. Absolutely positioned so a card with no image keeps its
   own height from the text fallback. */
.rail-card img{position:absolute;inset:8px;width:calc(100% - 16px);height:calc(100% - 16px);
  object-fit:contain;display:block;border-radius:12px;}
/* The dots grew from 5px to a 44px tap target below, so the margin comes down
   by the same amount the button's own padding now supplies: the bar still sits
   ~27px under the rail, exactly where it looked before. */
.rail-dots{display:flex;justify-content:center;gap:8px;margin-top:6px;}
/* The visible bar is 5px; the button is 44px. Drawing the bar as a pseudo
   element lets the real element carry the tap target, so this reads correctly
   to the accessibility tree as well as to a thumb, with no visual change.
   `min-height:0` used to override the site's own --tap token here. */
.rail-dots button{width:26px;height:var(--tap);background:none;position:relative;
  transition:width var(--dur-ui) var(--ease-soft);}
.rail-dots button::before{content:"";position:absolute;inset-inline:0;
  inset-block:calc(50% - 2.5px);border-radius:var(--r-pill);background:var(--line-2);
  transition:background var(--dur-micro) linear;}
.rail-dots button.active{width:38px;}
.rail-dots button.active::before{background:var(--lime);}
@media(max-width:1024px){.rail-track{--cols:min(4,var(--items,4));}}
@media(max-width:768px){.rail-track{--cols:min(2,var(--items,2));}
  .rail-arrow{display:none;}}

/* The same rail, carrying tournament cards instead of logo tiles. */
.rail-track--cards{--cols:3;grid-auto-columns:calc((100% - (var(--cols) - 1) * 24px) / var(--cols));
  gap:24px;padding-block:8px;align-items:stretch;}
.rail-track--cards .t-card{scroll-snap-align:start;height:100%;}
/* A lifting card would be clipped by the scroller, so inside the rail the
   hover moves the border and surface only. */
@media(hover:hover){
  .rail-track--cards .t-card:hover{transform:none;}
}
@media(max-width:1024px){.rail-track--cards{--cols:2;}}
@media(max-width:768px){.rail-track--cards{--cols:1;grid-auto-columns:86%;gap:16px;}}

/* ==========================================================================
   PROGRAMME CARDS - illustrated tiles used for the championship pipeline
   ========================================================================== */
.tile{background:var(--card);border:1.5px solid var(--line);border-radius:var(--r-card);
  padding:26px 24px 28px;display:flex;flex-direction:column;
  transition:transform var(--dur-ui) var(--ease-soft),background var(--dur-ui) linear,
             border-color var(--dur-micro) linear;}
@media(hover:hover){
  .tile:hover{transform:translateY(-6px);background:var(--card-2);border-color:var(--lime);}
}
.tile-art{height:150px;border-radius:var(--r-field);margin-bottom:20px;position:relative;overflow:hidden;
  background:linear-gradient(160deg,rgba(232,252,44,.16),rgba(232,252,44,.03));
  display:flex;align-items:center;justify-content:center;}
.tile-art::before{content:"";position:absolute;inset:0;
  background-image:radial-gradient(rgba(232,252,44,.5) 1px,transparent 1.5px);background-size:16px 16px;opacity:.24;}
.tile-art .ic{width:52px;height:52px;color:var(--lime);stroke-width:1.6;position:relative;}
.tile-art--navy{background:linear-gradient(160deg,var(--card-3),var(--card));}
.tile-art--navy .ic{color:var(--lime);}
.tile-art--navy::before{background-image:radial-gradient(rgba(232,252,44,.5) 1px,transparent 1.5px);opacity:.2;}
.tile-art--mint{background:linear-gradient(160deg,rgba(63,208,106,.16),rgba(63,208,106,.03));}
.tile-art--mint .ic{color:var(--ok);}
.tile-art--mint::before{background-image:radial-gradient(rgba(63,208,106,.5) 1px,transparent 1.5px);opacity:.2;}
.tile h3{margin-bottom:8px;}
.tile p{font-size:var(--t-md);color:var(--tx-2);}

/* ---------- Cards ----------
   Every panel sits on the same black family. The legacy rule that made light
   panels declare their own ink is inverted: panels declare white. */
.card,.form-card,.tile,.c-card,.match-card,
.rail-card,.stat,.feature-card,.t-card,.info-item,.team-row,.prize-card,
.acc-item,.modal{color:var(--tx-2);}
.dark .stat,.dark .t-card,.dark .info-item,.dark .team-row,.dark .prize-card{color:var(--tx-2);}
.feature-card--lead{color:var(--tx-2);}

.card{background:var(--card);border:1.5px solid var(--line);border-radius:var(--r-card);
  transition:transform var(--dur-ui) var(--ease-soft),background var(--dur-ui) linear,
             border-color var(--dur-micro) linear;}
@media(hover:hover){
  .card:hover{transform:translateY(-6px);background:var(--card-2);border-color:var(--line-2);}
}

/* A raised panel. On the old page this was the navy block on white; here it
   is the step up from the section ground. */
.panel-dark{background:var(--card);border:1.5px solid var(--line);color:var(--tx-2);}
@media(hover:hover){
  .panel-dark:hover{border-color:var(--line-2);}
}

/* ---------- Feature bento ----------
   Six capabilities, six cells, no empty tracks. Finding players is the reason
   the product exists, so it takes the tall cell. */
.feature-card{padding:34px 28px;border-radius:var(--r-card);background:var(--card);
  border:1.5px solid var(--line);position:relative;overflow:hidden;
  transition:transform var(--dur-ui) var(--ease-soft),background var(--dur-ui) linear,
             border-color var(--dur-micro) linear;}
@media(hover:hover){
  .feature-card:hover{transform:translateY(-6px);background:var(--card-2);border-color:var(--lime);}
}
.feature-icon{width:52px;height:52px;border-radius:var(--r-field);background:var(--lime);color:var(--lime-ink);
  display:flex;align-items:center;justify-content:center;margin-bottom:18px;}
.feature-card h3{margin-bottom:10px;}
.feature-card p{color:var(--tx-2);}
.feature-card .btn-sm{margin-top:20px;}
.feature-card--coach{background:linear-gradient(155deg,rgba(138,123,216,.14),var(--card));border-color:var(--info-line);}
.feature-card--coach .feature-icon{background:var(--info);color:var(--info-ink);}

.feature-bento{display:grid;grid-auto-flow:dense;gap:18px;grid-template-columns:repeat(4,minmax(0,1fr));}
.feature-bento > .feature-card{grid-column:span 2;}
.feature-bento > .feature-card--lead{grid-column:span 2;grid-row:span 2;}
.feature-bento > .feature-card:nth-child(2),
.feature-bento > .feature-card:nth-child(3){grid-column:span 1;}
/* The lead cell is the one place a whole card carries the brand colour, so it
   inverts: lime ground, black ink. It is the bento's focal point. */
.feature-card--lead{background:linear-gradient(150deg,var(--lime),var(--lime-dim));
  border-color:var(--lime);color:var(--lime-ink);
  display:flex;flex-direction:column;justify-content:flex-end;}
@media(hover:hover){
  .feature-card--lead:hover{background:linear-gradient(150deg,var(--lime-hi),var(--lime));border-color:var(--lime-hi);}
}
/* The lead card carries the photograph in its own colours, which makes it a
   panel rather than a wash: a colour photograph cannot dissolve into lime
   without going muddy through the transition, so it holds a clean edge and
   the card's own lime picks up below it. The panel is landscape because the
   space above the card's copy is a landscape band, and it occupies only that
   band. The copy begins at 62% of the card; the band stops short of it. */
.feature-card--lead .feature-art{
  position:absolute;inset-block-start:0;inset-inline:0;
  width:100%;height:58%;
  object-fit:cover;object-position:50% 45%;
  z-index:0;pointer-events:none;user-select:none;
  /* The join is stated rather than blurred — a hairline of the card's own
     ink, so it reads as a deliberate frame edge and not a photograph that
     simply ran out. */
  border-block-end:2px solid var(--lime-ink);}
.feature-card--lead > :not(.feature-art){position:relative;z-index:1;}
/* Nothing dims the photograph on hover: showing the lime through a fading
   colour image tints it, and the panel's whole point is its real colour. Only
   the card's own fill answers the pointer. */
/* Once the bento collapses, the lead card is no longer the tall cell it is on
   a wide screen — it is the same height as its neighbours, and a band set as a
   percentage of that would land straight on the copy. Below the collapse the
   band becomes a fixed strip and the card opens up enough room above its own
   content to hold it. */
@media(max-width:1024px){
  .feature-card--lead{padding-top:198px;}
  /* The collapsed band is far wider than the photograph's own proportions, so
     `cover` throws most of the frame's height away — at 820px it keeps only a
     third of it. Held at the middle that third lands across both players'
     heads, so the focal point moves up to where the faces and rackets are. */
  .feature-card--lead .feature-art{height:170px;object-position:50% 15%;}
}
@media(max-width:560px){
  .feature-card--lead{padding-top:170px;}
  .feature-card--lead .feature-art{height:144px;}
}
.feature-card--lead h3,.feature-card--lead .h3{color:var(--lime-ink);}
.feature-card--lead p{color:rgba(2,2,2,.72);}
.feature-card--lead .eyebrow{color:rgba(2,2,2,.66);}
.feature-card--lead .feature-icon{background:var(--lime-ink);color:var(--lime);}
.feature-card--lead .btn-outline-dark{background:rgba(2,2,2,.08);border-color:rgba(2,2,2,.34);color:var(--lime-ink);}
@media(hover:hover){
  .feature-card--lead .btn-outline-dark:hover{background:var(--lime-ink);border-color:var(--lime-ink);color:var(--lime);}
}
@media(max-width:1024px){
  .feature-bento{grid-template-columns:repeat(2,minmax(0,1fr));}
  .feature-bento > .feature-card,
  .feature-bento > .feature-card--lead{grid-column:span 1;grid-row:auto;}
}
@media(max-width:768px){.feature-bento{grid-template-columns:1fr;}
  .feature-bento > .feature-card{grid-column:span 1;}}

/* ---------- Tournament card ---------- */
.t-card{background:var(--card);border:1.5px solid var(--line);border-radius:var(--r-card);
  overflow:hidden;display:flex;flex-direction:column;
  transition:transform var(--dur-ui) var(--ease-soft),background var(--dur-ui) linear,
             border-color var(--dur-micro) linear;}
@media(hover:hover){
  .t-card:hover{transform:translateY(-8px);background:var(--card-2);border-color:var(--lime);}
}
.dark .t-card{background:var(--card);border-color:var(--line);}
.t-poster{position:relative;aspect-ratio:16/9;overflow:hidden;background:var(--card-3);}
.t-poster img,.t-poster svg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;}
/* Supplied photography is shot in daylight and would read as a lit window cut
   into a night page. A light grade and a scrim seat it in the same scene and
   give the status chip and tags something to sit on. The grade is deliberately
   gentle: enough to belong, not so much that the court stops being green. */
.t-poster img{filter:brightness(.84) saturate(.9) contrast(1.06);
  transition:filter var(--dur-ui) var(--ease-soft);}
@media(hover:hover){
  .t-card:hover .t-poster img{filter:brightness(.96) saturate(1) contrast(1.04);}
}
.t-poster::after{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(to bottom,rgba(2,2,2,.42) 0%,rgba(2,2,2,0) 34%,
             rgba(2,2,2,0) 52%,rgba(2,2,2,.62) 100%);}
.status-chip{position:absolute;top:16px;inset-inline-start:16px;
  background:var(--ok);color:var(--ok-ink);display:inline-flex;align-items:center;gap:7px;
  font-size:var(--t-xs);font-weight:800;padding:7px 14px;border-radius:var(--r-pill);z-index:2;}
.status-chip::before{content:"";width:6px;height:6px;border-radius:var(--r-round);background:currentColor;opacity:.7;}
.status-chip.closed{background:var(--card-3);color:var(--tx);border:1px solid var(--line-2);}
.status-chip.live{background:var(--lime);color:var(--lime-ink);}
.status-chip.done{background:var(--card-2);color:var(--tx-3);border:1px solid var(--line-2);}
.status-chip.soon{background:var(--info);color:var(--info-ink);}
/* Category and level ride on the poster rather than taking two rows in the
   body: they are how a player filters, so they belong with the artwork. */
.t-tags{position:absolute;bottom:14px;inset-inline-start:14px;z-index:2;
  display:flex;gap:8px;flex-wrap:wrap;max-inline-size:calc(100% - 28px);}
.t-tag{background:rgba(2,2,2,.86);color:var(--tx);font-size:var(--t-xs);font-weight:800;
  padding:6px 13px;border-radius:var(--r-pill);
  border:1px solid rgba(255,255,255,.18);}
.t-tag:empty{display:none;}

/* `min-width` is the load-bearing word here. The body is a flex item, and in
   the wide variant below the card turns into a row, so the body's width is
   decided by the flex algorithm instead of by a grid track. With the default
   `min-width:auto` it could not be shrunk below its own min-content width,
   which the prize pill used to push to 928px: the body overflowed the 659px
   the poster left it and the card's `overflow:hidden` cut the difference off
   the inline start — the prize ran off the edge and the registered-teams
   count was clipped away entirely. */
.t-body{padding:24px 24px 26px;display:flex;flex-direction:column;flex:1;min-width:0;}
.t-cat{font-size:var(--t-xs);color:var(--lime);font-weight:800;margin-bottom:6px;}
.dark .t-cat,.panel-dark .t-cat,.prize-hero .t-cat{color:var(--lime);}
.t-body h3{margin-bottom:16px;}

/* Date, time, court and fee read as a 2x2 block of label-over-value pairs.
   Stacked rows would run to eight lines and the card would stop scanning. */
.t-specs{display:grid;grid-template-columns:1fr 1fr;gap:14px 12px;margin-bottom:16px;}
.t-spec{min-width:0;}
.t-spec dt{display:flex;align-items:center;gap:6px;font-size:var(--t-xs);font-weight:700;
  color:var(--tx-3);margin-bottom:3px;}
.t-spec dd{font-size:var(--t-sm);font-weight:800;color:var(--tx);font-variant-numeric:tabular-nums;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.t-spec .ic{width:14px;height:14px;color:var(--tx-3);flex-shrink:0;}
.dark .t-spec dt{color:var(--tx-3);}
.dark .t-spec dd{color:var(--tx);}
.dark .t-spec .ic{color:var(--tx-3);}

/* The prize is the one place on the card that carries gold, because the prize
   is the only thing on it that is actually won. */
/* The prize wraps, at every width, and this is the rule that keeps the card
   in one piece. `white-space:nowrap` on the value made its min-content width
   the full length of the sentence — 840px for the longest prize in the
   database — and `min-width:0` does not cap that: it lifts the automatic
   minimum during layout but an intrinsic size still walks up through the
   flex parents. So `.t-prize` handed `.t-body` a 840px floor, and the wide
   card could not lay the body out inside the room it had.
   Wrapping is also what a reader wants. A phone already wrapped it here for
   exactly that reason: the pill is 285px and a single clipped line showed
   195px of a 849px prize — "The tournament troph...". The same is true of a
   240px card on the home rail, which showed a third of it. One behaviour at
   every width, rather than one per breakpoint. The pill loses its full round
   because it is no longer always one line high. */
.t-prize{display:flex;align-items:flex-start;gap:9px;margin-bottom:18px;
  background:var(--gold-bg);border:1px solid var(--gold-line);
  border-radius:var(--r-field);padding:10px 15px;min-width:0;}
.t-prize .ic{width:15px;height:15px;color:var(--gold);flex-shrink:0;margin-top:1px;}
.t-prize-k{font-size:var(--t-xs);font-weight:700;color:var(--tx-3);flex-shrink:0;margin-top:1px;}
.t-prize b{font-size:var(--t-sm);font-weight:800;color:var(--gold);min-width:0;
  overflow-wrap:anywhere;}

.dark .t-prize{background:var(--gold-bg);}
.dark .t-prize .ic{color:var(--gold);}
.dark .t-prize-k{color:var(--tx-3);}
.dark .t-prize b{color:var(--gold);}

.t-progress-wrap{margin-bottom:20px;margin-top:auto;}
.t-progress-label{display:flex;justify-content:space-between;font-size:var(--t-xs);color:var(--tx-3);
  margin-bottom:7px;font-variant-numeric:tabular-nums;}
.dark .t-progress-label{color:var(--tx-3);}
.t-progress-label b{color:var(--lime);}
.dark .t-progress-label b{color:var(--lime);}
.t-progress{height:6px;background:var(--card-3);border-radius:var(--r-pill);overflow:hidden;}
.dark .t-progress{background:var(--card-3);}
.t-progress i{display:block;height:100%;background:var(--lime);border-radius:var(--r-pill);
  transition:width .6s var(--ease);}
/* `.btn` is `white-space:nowrap`, so a button can never be laid out narrower
   than its own label. `flex:1` sets a flex-basis of 0, which tells the row
   both buttons always fit — so they never wrapped, and whatever did not fit
   simply ran out of the card. A breakpoint only moved the problem: below
   768px the row stacked, but the same two buttons needed 383px inside a
   302px card in the three-up grid at 1024, and "Tournament details" hung 82px
   past the edge with the card's `overflow:hidden` cutting it in half.
   Sizing from the label instead lets the row decide for itself: the two sit
   side by side wherever both fit, and the moment they do not, the second one
   takes the next line — at any width, in either language, whatever the state
   of the tournament makes the labels say. */
.t-actions{display:flex;gap:10px;flex-wrap:wrap;}
.t-actions .btn{flex:1 1 auto;}
/* Below the phone breakpoint they stack whether or not they would fit: side
   by side is a desktop luxury. */
@media(max-width:768px){
  .t-actions .btn{flex:1 1 100%;}
}
.t-card .btn-outline,.dark .t-card .btn-outline,.dark .t-actions .btn-outline{
  background:transparent;border:1.5px solid var(--line-ctl);color:var(--tx);}
@media(hover:hover){
  .t-card .btn-outline:hover,.dark .t-card .btn-outline:hover{
    background:var(--lime-bg);border-color:var(--lime);color:var(--lime);}
}
.trn-poster-hero{border-radius:var(--r-card);overflow:hidden;}

/* ---------- Court card ---------- */
.c-card{border-radius:var(--r-card);overflow:hidden;background:var(--card);border:1.5px solid var(--line);
  display:flex;flex-direction:column;
  transition:transform var(--dur-ui) var(--ease-soft),background var(--dur-ui) linear,
             border-color var(--dur-micro) linear;}
@media(hover:hover){
  .c-card:hover{transform:translateY(-6px);background:var(--card-2);border-color:var(--lime);}
}
.c-media{aspect-ratio:4/3;position:relative;overflow:hidden;display:flex;align-items:center;justify-content:center;
  background:linear-gradient(150deg,var(--card-3),var(--card));}
.c-media::before{content:"";position:absolute;inset:0;
  background-image:radial-gradient(rgba(232,252,44,.45) 1px,transparent 1.5px);background-size:18px 18px;opacity:.14;}
.c-media .ic-lg{color:var(--lime);width:44px;height:44px;opacity:.5;position:relative;}
.c-media img,.c-media svg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;}
/* Same grade as the tournament poster, so photography reads as one set. A
   partner logo on its white plate opts out — grading a trademark is not ours
   to do. */
.c-media img:not(.on-light-plate){filter:brightness(.84) saturate(.9) contrast(1.06);
  transition:filter var(--dur-ui) var(--ease-soft);}
@media(hover:hover){
  .c-card:hover .c-media img:not(.on-light-plate){filter:brightness(.96) saturate(1) contrast(1.04);}
}
.c-media::after{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(to bottom,rgba(2,2,2,0) 46%,rgba(2,2,2,.55) 100%);}
.c-media:has(.on-light-plate)::after{display:none;}
.c-content{padding:22px 24px 26px;}
.c-content h3{margin-bottom:8px;}
.c-content p{color:var(--tx-2);}
.c-meta-row{display:flex;flex-wrap:wrap;gap:8px;margin-top:14px;}

/* ---------- Pills ---------- */
.pill{display:inline-flex;align-items:center;gap:6px;padding:8px 14px;border-radius:var(--r-pill);
  font-size:var(--t-xs);font-weight:800;background:var(--card-2);color:var(--tx-2);
  border:1px solid var(--line);}
.pill .ic{width:14px;height:14px;}
.pill-gold{background:var(--gold-bg);color:var(--gold);border-color:var(--gold-line);}
.pill-green{background:var(--ok-bg);color:var(--ok);border-color:var(--ok-line);}
.pill-purple{background:var(--info-bg);color:var(--info-tx);border-color:var(--info-line);}
.pill-navy{background:var(--lime-bg);color:var(--lime);border-color:var(--lime-line);}
.pill-red{background:var(--danger-bg);color:var(--danger);border-color:var(--danger-line);}
.pill-outline{background:transparent;border:1.5px solid var(--line-2);color:var(--tx-2);}

/* ---------- Stats ---------- */
/* The owner adds and removes counters from the dashboard now, so the row
   cannot assume four: a fifth used to drop onto a line of its own. */
.stats-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:18px;}
.stat{background:var(--card);border:1.5px solid var(--line);border-radius:var(--r-card);
  padding:30px 20px;text-align:center;transition:border-color var(--dur-micro) linear,background var(--dur-ui) linear;}
@media(hover:hover){
  .stat:hover{border-color:var(--lime);background:var(--card-2);}
}
.stat b{display:block;font-size:clamp(1.9rem,3vw,2.7rem);font-weight:900;color:var(--lime);line-height:1.1;
  font-variant-numeric:tabular-nums;}
.stat span{font-size:var(--t-sm);color:var(--tx-3);font-weight:700;}
.dark .stat{background:var(--card);border-color:var(--line);}
.dark .stat b{color:var(--lime);}
.dark .stat span{color:var(--tx-3);}
@media(max-width:768px){.stats-row{grid-template-columns:repeat(2,1fr);}}

/* ---------- Grid ---------- */
.grid{display:grid;gap:24px;}
.grid-2{grid-template-columns:1fr 1fr;}
.grid-3{grid-template-columns:repeat(3,1fr);}
.grid-4{grid-template-columns:repeat(4,1fr);}
.grid-6{grid-template-columns:repeat(6,1fr);}
@media(max-width:1024px){.grid-4{grid-template-columns:repeat(2,1fr);} .grid-6{grid-template-columns:repeat(3,1fr);}}
/* One place where the grids collapse, instead of `.grid-2` being declared
   here and again in a wider query that made this copy unreachable. */
@media(max-width:768px){.grid-2,.grid-3,.grid-4{grid-template-columns:1fr;}
  .grid-6{grid-template-columns:repeat(2,1fr);} .sticky-side{position:static;}}

/* ---------- Reveal ----------
   Only transform and opacity animate, so each reveal stays on the compositor. */
.reveal{transition:opacity var(--dur-enter) var(--ease),transform var(--dur-enter) var(--ease);}
.js-ready .reveal{opacity:0;transform:translateY(30px);}
.js-ready .reveal.in-view{opacity:1;transform:none;}
/* start and end are logical names that were implemented physically: in
   Arabic, start is the right edge, so every start reveal slid in from the
   wrong side. The base case is the primary language and the Latin override
   follows it, the same pattern the hero scrim and the button icon use. */
.js-ready .reveal[data-reveal=start]{transform:translateX(40px);}
.js-ready .reveal[data-reveal=end]{transform:translateX(-40px);}
[dir=ltr] .js-ready .reveal[data-reveal=start],
[dir=ltr].js-ready .reveal[data-reveal=start]{transform:translateX(-40px);}
[dir=ltr] .js-ready .reveal[data-reveal=end],
[dir=ltr].js-ready .reveal[data-reveal=end]{transform:translateX(40px);}
.js-ready .reveal[data-reveal=media]{transform:scale(.95);}
.js-ready .reveal[data-reveal=rise]{transform:translateY(56px);}
.js-ready .reveal[data-reveal].in-view{transform:none;}
.stagger > *{transition-delay:calc(var(--i,0) * 80ms);}
@media(prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;
    transition-duration:.01ms!important;scroll-behavior:auto!important;}
  .js-ready .reveal{opacity:1!important;transform:none!important;}
}

/* ---------- Page hero (inner pages) ---------- */
.page-hero{background:var(--surface);color:var(--tx-2);position:relative;overflow:hidden;
  padding:calc(var(--nav-h) + 56px) 0 60px;border-bottom:1px solid var(--line);}
/* The chevron ground, cut into the band rather than dotted over it. */
.page-hero::before{content:"";position:absolute;inset:0;pointer-events:none;
  background:
    linear-gradient(115deg,transparent 22%,#0D0D10 22%,#0D0D10 40%,transparent 40%),
    linear-gradient(-115deg,transparent 58%,#0B0B0E 58%,#0B0B0E 76%,transparent 76%);}
.page-hero .container{position:relative;z-index:2;}
.page-hero .h1{max-width:20ch;}
.page-hero .lead{color:var(--tx-2);}
.page-hero .glow-field::before{opacity:.32;}
.page-hero .glow-blob{opacity:.1;transform:scale(2.05);}

/* The partner page opens on the partner: the copy on the start side and the
   mark large on the other, instead of a 118px tile stacked over a centred
   title. That title also sat off-centre, because `.page-hero .h1` caps it at
   20ch and nothing centred the narrower block; start-aligned copy has no
   centre to miss. On a phone the mark comes first, under the breadcrumbs. */
.partner-hero{text-align:start;}
.partner-hero .crumbs{justify-content:flex-start;}
.partner-hero__grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:clamp(28px,5vw,72px);align-items:center;margin-top:28px;}
.partner-hero__mark{width:100%;max-width:460px;aspect-ratio:1 / 1;justify-self:center;
  border-radius:var(--r-card);background:var(--card);border:1.5px solid var(--line);}
@media(max-width:768px){
  .partner-hero__grid{grid-template-columns:1fr;gap:26px;}
  .partner-hero__mark{order:-1;max-width:360px;}
}
.crumbs{display:flex;align-items:center;gap:8px;font-size:var(--t-sm);color:var(--tx-3);
  margin-bottom:18px;flex-wrap:wrap;font-weight:600;}
@media(hover:hover){
  .crumbs a:hover{color:var(--lime);}
}

/* ---------- Tabs ---------- */
.tabs-nav{display:flex;gap:8px;overflow-x:auto;padding-bottom:4px;margin-bottom:32px;}
.tabs-nav button{padding:12px 22px;border-radius:var(--r-pill);font-weight:800;font-size:var(--t-md);
  white-space:nowrap;background:var(--card);border:1.5px solid var(--line-ctl);color:var(--tx-2);
  transition:background var(--dur-micro) linear,color var(--dur-micro) linear,border-color var(--dur-micro) linear;}
@media(hover:hover){
  .tabs-nav button:hover{border-color:rgba(255,255,255,.52);color:var(--tx);}
}
.tabs-nav button:active{transform:scale(.97);}
.tabs-nav button[disabled]{opacity:.45;pointer-events:none;}
.tabs-nav button.active{background:var(--lime);border-color:var(--lime);color:var(--lime-ink);}
.tab-panel{display:none;}
.tab-panel.active{display:block;animation:fadein .5s var(--ease);}
@keyframes fadein{from{opacity:0;transform:translateY(10px);}to{opacity:1;transform:none;}}

/* ---------- Row card ----------
   One row with something on each end: a tournament on a court's page, a
   reward under its sponsor, a prize under the business that provides it. It
   was built for the fixture lists, and its inner parts (`.match-teams`,
   `.vs`, `.match-meta`, `.match-status`) went with them — the two teams, the
   kick-off time and the played/not-played pill have nowhere left to be
   drawn, because a match is emailed to the two teams and published nowhere.
   The row itself carries three pages, so it stays. */
.match-card{display:flex;align-items:center;justify-content:space-between;gap:18px;
  background:var(--card);border:1.5px solid var(--line);border-radius:var(--r-card);
  padding:20px 24px;margin-bottom:12px;flex-wrap:wrap;
  transition:border-color var(--dur-micro) linear,background var(--dur-ui) linear;}
@media(hover:hover){
  .match-card:hover{border-color:var(--lime);background:var(--card-2);}
}
@media(max-width:768px){.match-card{flex-direction:column;align-items:flex-start;}}

/* No standings table survives on the public site: there are no results to
   build one from. The `.standings` block went first, then `.rank-num`, which
   numbered the rows of the group tables on tournament.html and had no other
   reader. `.overflow-x` stays — it is the dashboard's scroll frame for every
   wide `.a-table`. */
.overflow-x{overflow-x:auto;}

/* The knockout chart is drawn by assets/js/bracket.js into assets/css/bracket.css's
   own `.mmb-*` classes, and only the dashboard draws it. The `.bracket-*`,
   `.champ-card` and `.champ-cup` rules that used to sit here were left behind
   by the chart this site no longer has, and no page referenced them. */

/* ---------- Forms ---------- */
.field{margin-bottom:20px;}
.field label{display:block;font-size:var(--t-sm);font-weight:800;margin-bottom:9px;color:var(--tx);}
.field label .req{color:var(--danger);}
/* The field's background is --card and a .form-card's background is --card too,
   so inside a form the only thing that says "this is an input" is its border.
   At --line-2 that border was 1.40:1 against its own fill; it takes the control
   line now, which clears 3:1. */
/* 16px is a hard floor, not a preference: iOS Safari zooms the viewport on
   focus for anything smaller and never zooms back out, so a visitor who taps
   the first field fills in the rest of the form zoomed in. This was .95rem,
   which computes to 15.2px. */
.field input,.field select,.field textarea{width:100%;padding:15px 18px;border:1.5px solid var(--line-ctl);
  border-radius:var(--r-field);font-size:var(--t-control);background:var(--card);color:var(--tx);
  transition:border-color var(--dur-micro) linear,box-shadow var(--dur-micro) linear,
             background var(--dur-micro) linear;}
.field input::placeholder,.field textarea::placeholder{color:var(--tx-3);}
/* Hover used to restate --line-2, the rest colour, so the border did not move
   at all. It steps up now. */
@media(hover:hover){
  .field input:hover,.field select:hover,.field textarea:hover{border-color:rgba(255,255,255,.52);
    background-color:var(--card-2);}
}
.field input:disabled,.field select:disabled,.field textarea:disabled,
.field input[readonly],.field textarea[readonly]{opacity:.5;cursor:not-allowed;
  background-color:var(--surface);border-color:var(--line-2);}
@media(hover:hover){
  .field input:disabled:hover,.field select:disabled:hover,.field textarea:disabled:hover{
    border-color:var(--line-2);background-color:var(--surface);}
}
/* `outline:none` on a bare :focus outranks the global :focus-visible ring and
   was deleting it for keyboard users. Scoped to :not(:focus-visible) it only
   quiets the mouse-click case, and the mandated lime ring survives. */
.field input:focus,.field select:focus,.field textarea:focus{border-color:var(--lime);
  background-color:var(--card-2);box-shadow:0 0 0 4px rgba(232,252,44,.16);}
.field input:focus:not(:focus-visible),.field select:focus:not(:focus-visible),
.field textarea:focus:not(:focus-visible){outline:none;}
/* The native select arrow is drawn black by the UA on some platforms, which
   disappears on this ground, so the control draws its own chevron — and every
   state above paints `background-color`, never the `background` shorthand,
   because the shorthand also resets background-size and background-position:
   the chevron grew to fill the whole control on focus and vanished on hover.
   `color-scheme` is what makes the platform draw the open list dark instead
   of a white sheet with black rows. */
.field select{appearance:none;-webkit-appearance:none;color-scheme:dark;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23ffffff' stroke-opacity='.62' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6.25 8 10.25l4-4'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:calc(100% - 18px) center;
  background-size:15px 15px;padding-inline-end:46px;}
[dir=rtl] .field select{background-position:18px center;
  padding-inline-end:18px;padding-inline-start:46px;}
.field select:focus{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23E8FC2C' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6.25 8 10.25l4-4'/%3E%3C/svg%3E");}
.field select option{background:var(--card-2);color:var(--tx);}
/* Nothing chosen yet reads as a placeholder, the way the text inputs do. */
.field select:invalid,.field select:has(option[value=""]:checked),
.field select option[value=""]{color:var(--tx-3);}
.field textarea{resize:vertical;min-height:120px;}
.field .hint{font-size:var(--t-xs);color:var(--tx-3);margin-top:6px;}
.field.err input,.field.err select,.field.err textarea{border-color:var(--danger);}
.field .err-msg{display:none;font-size:var(--t-xs);color:var(--danger);margin-top:6px;font-weight:700;}
.field.err .err-msg{display:block;}
.form-card{background:var(--card);border:1.5px solid var(--line);border-radius:var(--r-card);
  padding:38px;}
.form-section-title{display:flex;align-items:center;gap:12px;font-weight:900;font-size:1.1rem;
  margin-bottom:22px;color:var(--tx);}
.form-section-title .num{width:30px;height:30px;border-radius:var(--r-round);background:var(--lime);
  color:var(--lime-ink);display:flex;align-items:center;justify-content:center;font-size:var(--t-sm);
  font-weight:900;flex-shrink:0;}
.divider{height:1px;background:var(--line);margin:32px 0;}
.checkbox-row{display:flex;align-items:flex-start;gap:12px;font-size:var(--t-sm);color:var(--tx-2);cursor:pointer;}
.checkbox-row input{width:20px;height:20px;margin-top:2px;accent-color:var(--lime);flex-shrink:0;cursor:pointer;}
@media(max-width:768px){.form-card{padding:24px;}}

/* ---------- Summary / review ---------- */
.summary-list{display:flex;flex-direction:column;}
.summary-list li{display:flex;justify-content:space-between;padding:16px 0;
  border-bottom:1px solid var(--line);font-size:var(--t-md);gap:20px;}
.summary-list li span:first-child{color:var(--tx-3);}
.summary-list li span:last-child{font-weight:800;text-align:end;color:var(--tx);
  font-variant-numeric:tabular-nums;}
.summary-list li.total{border-bottom:none;padding-top:22px;font-size:1.15rem;}
.summary-list li.total span:last-child{color:var(--lime);font-size:1.4rem;font-weight:900;}

/* ---------- Accordion ---------- */
.acc-item{border-bottom:1px solid var(--line);}
.acc-trigger{width:100%;display:flex;align-items:center;justify-content:space-between;padding:24px 4px;
  font-weight:800;font-size:1.02rem;text-align:start;gap:20px;color:var(--tx);}
/* A full-width clickable row that gave no sign it was clickable. */
@media(hover:hover){
  .acc-trigger:hover{color:var(--lime);}
}
@media(hover:hover){
  .acc-trigger:hover .plus{background:var(--card-3);}
}
.acc-trigger:active{transform:scale(.995);}
.acc-trigger[disabled]{opacity:.45;pointer-events:none;}
.acc-trigger .plus{width:34px;height:34px;border-radius:var(--r-round);background:var(--card-2);flex-shrink:0;
  display:flex;align-items:center;justify-content:center;position:relative;
  transition:transform .4s var(--ease-soft),background var(--dur-micro) linear;}
.acc-trigger .plus::before,.acc-trigger .plus::after{content:"";position:absolute;
  background:var(--tx);border-radius:2px;}
.acc-trigger .plus::before{width:12px;height:2px;}
.acc-trigger .plus::after{width:2px;height:12px;transition:transform .3s;}
.acc-item.open .acc-trigger .plus{background:var(--lime);transform:rotate(180deg);}
.acc-item.open .acc-trigger .plus::before,.acc-item.open .acc-trigger .plus::after{background:var(--lime-ink);}
.acc-item.open .acc-trigger .plus::after{transform:scaleY(0);}
.acc-panel{max-height:0;overflow:hidden;transition:max-height .45s var(--ease);}
.acc-panel-inner{padding:0 4px 24px;color:var(--tx-2);font-size:var(--t-md);max-width:65ch;}

/* ---------- Video grid ---------- */
.video-card{position:relative;border-radius:var(--r-card);overflow:hidden;aspect-ratio:16/10;
  background:linear-gradient(140deg,var(--card-3),var(--card));cursor:pointer;
  border:1.5px solid var(--line);transition:border-color var(--dur-micro) linear;}
@media(hover:hover){
  .video-card:hover{border-color:var(--lime);}
}
.video-card::before{content:"";position:absolute;inset:0;
  background-image:radial-gradient(rgba(232,252,44,.4) 1px,transparent 1.4px);
  background-size:18px 18px;opacity:.12;}
.video-card img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:1;}
.video-play{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;z-index:2;}
.video-play span{width:64px;height:64px;border-radius:var(--r-round);background:rgba(2,2,2,.66);display:flex;align-items:center;justify-content:center;
  border:1px solid rgba(255,255,255,.24);
  transition:background var(--dur-micro) linear,transform var(--dur-ui) var(--ease-soft),
             border-color var(--dur-micro) linear;}
@media(hover:hover){
  .video-card:hover .video-play span{background:var(--lime);border-color:var(--lime);transform:scale(1.1);}
}
@media(hover:hover){
  .video-card:hover .video-play span .ic{color:var(--lime-ink);}
}
.video-play .ic{color:var(--tx);width:22px;height:22px;}
.video-tag{position:absolute;bottom:16px;inset-inline:16px;color:var(--tx);font-weight:800;font-size:var(--t-md);
  z-index:2;text-shadow:0 2px 12px rgba(0,0,0,.85);}
.video-dur{position:absolute;top:14px;inset-inline-end:14px;background:rgba(2,2,2,.82);color:var(--tx);
  font-size:var(--t-xs);font-weight:800;padding:4px 10px;border-radius:8px;z-index:2;direction:ltr;
  border:1px solid rgba(255,255,255,.14);font-variant-numeric:tabular-nums;}

/* The champion spotlight (`.champion-row`, `.champion-media`,
   `.champion-info`, `.trophy-badge`) stood here. It drew one block per
   crowned team on the wall of champions, the only block on the site allowed
   to be gold throughout. A Match Me tournament has no champion any more — the
   page it belonged to is gone and nothing else ever used these rules. */

/* ---------- Utilities ---------- */
/* The tournament picker's summary. A native <option> cannot wrap, so the
   five facts that used to be crushed into its label live here instead, where
   they have room to be read — and where the fee, which the visitor is about
   to be charged, is legible before they commit to it. */
.trn-summary{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));
  gap:2px 18px;margin-top:12px;padding:14px 16px;background:var(--card-2);
  border:1px solid var(--line);border-radius:var(--r-field);}
.trn-summary > div{display:flex;align-items:baseline;justify-content:space-between;
  gap:12px;padding:5px 0;min-width:0;}
.trn-summary dt{font-size:var(--t-xs);color:var(--tx-3);flex-shrink:0;}
.trn-summary dd{font-size:var(--t-sm);font-weight:700;color:var(--tx);text-align:end;min-width:0;}
.trn-summary b{color:var(--lime);}

/* A text column beside an illustration. The tracks are content-sized, so at
   phone width the first one refused to go under 319px and pushed the second
   clean off the viewport — the phone illustration sat at x=420 on a 375px
   screen and was never seen by anyone on a phone. */
.card-split{display:grid;grid-template-columns:1.2fr .8fr;gap:40px;align-items:center;padding:40px;}
.card-split > *{min-width:0;}
@media(max-width:768px){
  .card-split{grid-template-columns:1fr;gap:28px;padding:28px 22px;}
}

.flex{display:flex;} .flex-center{display:flex;align-items:center;justify-content:center;}
.flex-between{display:flex;align-items:center;justify-content:space-between;}
.gap-8{gap:8px;} .gap-12{gap:12px;} .gap-16{gap:16px;} .gap-20{gap:20px;} .gap-30{gap:30px;}
.mt-8{margin-top:8px;} .mt-16{margin-top:16px;} .mt-24{margin-top:24px;}
.mt-40{margin-top:40px;} .mt-60{margin-top:60px;}
.mb-16{margin-bottom:16px;} .mb-24{margin-bottom:24px;} .mb-40{margin-bottom:40px;}
.text-center{text-align:center;} .text-muted{color:var(--tx-3);}
.sticky-side{position:sticky;top:calc(var(--nav-h) + 24px);}
/* A latin run inside an Arabic sentence: a phone number, a URL, a count.
   `display:inline-block` is part of that job on a SPAN inside running text —
   it keeps the run in one unbreakable box — but it is a trap on anything that
   is already a box of its own. Put `.ltr` on a <td>, a <th>, or a flex/grid
   child and the element leaves the layout its parent gave it: a dashboard
   table cell became an inline-block INSIDE its cell and drew a second, offset
   border inside the row. For those, use `.ltr-box` below: the same isolation,
   with the element's own display left alone.
   Nothing in the repo relies on the inline-block today — the one <td class=
   "ltr"> left is in _tools/teams-dev.html, a dev scratch page — so `.ltr`
   keeps its behaviour and the companion is the fix for the next person. */
.ltr{direction:ltr;unicode-bidi:isolate;display:inline-block;}
/* Same isolation, no display change. For a table cell, a flex/grid child, or
   anything else whose box is not this class's business. */
.ltr-box{direction:ltr;unicode-bidi:isolate;}
.avatar{width:46px;height:46px;border-radius:var(--r-round);background:var(--lime);color:var(--lime-ink);
  font-weight:900;display:flex;align-items:center;justify-content:center;flex-shrink:0;}
/* `.grid-2` and `.sticky-side` collapse with the rest of the grids, at 768.
   Sending them to 1024 instead stacked a two-column grid that still had 427px
   per column at a 950px window — longer page, no gain. */

/* ---------- Filter chips ---------- */
.filter-chips{display:flex;gap:10px;flex-wrap:wrap;margin-bottom:34px;}
.filter-chips button{padding:11px 22px;border-radius:var(--r-pill);font-weight:800;font-size:var(--t-sm);
  background:var(--card);border:1.5px solid var(--line-ctl);color:var(--tx-2);
  transition:background var(--dur-micro) linear,color var(--dur-micro) linear,border-color var(--dur-micro) linear;}
@media(hover:hover){
  .filter-chips button:hover{border-color:rgba(255,255,255,.52);color:var(--tx);}
}
.filter-chips button:active{transform:scale(.97);}
.filter-chips button[disabled]{opacity:.45;pointer-events:none;}
.filter-chips button.active{background:var(--lime);border-color:var(--lime);color:var(--lime-ink);}
.dark .filter-chips button{background:var(--card);border-color:var(--line-ctl);color:var(--tx-2);}
.dark .filter-chips button.active{background:var(--lime);border-color:var(--lime);color:var(--lime-ink);}

/* ---------- Modal ---------- */
.modal-back{position:fixed;inset:0;background:rgba(0,0,0,.78);backdrop-filter:blur(8px);z-index:400;
  display:flex;align-items:center;justify-content:center;padding:24px;opacity:0;pointer-events:none;
  transition:opacity .3s var(--ease);}
.modal-back.open{opacity:1;pointer-events:auto;}
.modal{background:var(--card);border:1.5px solid var(--line-2);border-radius:var(--r-card);
  /* `vh` on iOS is the viewport with the address bar retracted, so this
     measured against a height the visitor does not have yet. */
  max-width:560px;width:100%;max-height:88dvh;
  overflow-y:auto;padding:36px;position:relative;box-shadow:var(--shadow-lg);
  transform:translateY(24px) scale(.97);transition:transform .4s var(--ease);
  /* A dialog taller than 88dvh scrolls, and the browser's default scrollbar is
     a light grey slab down the edge of a near-black panel. The dashboard used
     to fix this on itself with a local class; every other dialog on the site
     has the same surface and the same defect, so it is the default here. */
  scrollbar-width:thin;scrollbar-color:var(--line-2) transparent;}
.modal::-webkit-scrollbar{width:12px;}
.modal::-webkit-scrollbar-track{background:transparent;}
.modal::-webkit-scrollbar-thumb{background:var(--line-2);border-radius:999px;
  border:4px solid transparent;background-clip:content-box;}
@media(hover:hover){
  .modal::-webkit-scrollbar-thumb:hover{background:var(--tx-3);background-clip:content-box;}
}
.modal-back.open .modal{transform:none;}
.modal.wide{max-width:860px;}
.modal.dark-modal{background:var(--card);color:var(--tx-2);}
.modal h2,.modal h3,.modal .h2,.modal .h3{color:var(--tx);}
.modal-close{position:absolute;top:18px;inset-inline-start:18px;width:38px;height:38px;
  border-radius:var(--r-round);background:var(--card-3);color:var(--tx);display:flex;align-items:center;
  justify-content:center;z-index:2;transition:background var(--dur-micro) linear,color var(--dur-micro) linear;}
.modal.dark-modal .modal-close{background:var(--card-3);color:var(--tx);}
@media(hover:hover){
  .modal-close:hover{background:var(--lime);color:var(--lime-ink);}
}
.modal-close:active{transform:scale(.92);}
/* .modal-close is parked at inset-inline-start — in Arabic, the very corner
   the first line of the dialog starts in. «حمّل التطبيق» read as «حقل التطبيق»
   in the download dialog and the dashboard's «راعٍ جديد» as «ع جديد»: the
   opening letters sat under the button. 46px is the button's 18px offset plus
   its 38px width, less the overlap the round corner allows.
   Scoped to the element that actually follows the button, and only when that
   element is a heading or an eyebrow — a dialog whose first child is a video
   frame or an image must keep the full width it was given. */
.modal > .modal-close + h2,
.modal > .modal-close + h3,
.modal > .modal-close + .eyebrow{padding-inline-start:46px;}

/* ---------- Toast ---------- */
/* Toasts are transient and appear exactly where the home indicator lives. */
.toast-zone{position:fixed;bottom:calc(26px + env(safe-area-inset-bottom,0px));
  left:50%;transform:translateX(-50%);z-index:500;
  display:flex;flex-direction:column;gap:10px;align-items:center;pointer-events:none;width:min(92vw,480px);}
.toast{background:var(--card-3);color:var(--tx);border:1px solid var(--line-2);
  padding:14px 24px;border-radius:var(--r-pill);
  font-weight:800;font-size:var(--t-md);box-shadow:var(--shadow-lg);display:flex;align-items:center;gap:10px;
  animation:toastin .45s var(--ease);max-width:100%;}
.toast.ok{background:var(--ok);color:var(--ok-ink);border-color:var(--ok);}
.toast.warn{background:var(--lime);color:var(--lime-ink);border-color:var(--lime);}
.toast.err{background:var(--danger);color:var(--danger-ink);border-color:var(--danger);}
@keyframes toastin{from{opacity:0;transform:translateY(18px);}to{opacity:1;transform:none;}}
.toast.out{opacity:0;transform:translateY(12px);transition:.4s;}

/* ---------- Download modal ---------- */
.store-badges--lg{margin-top:22px;}
.qr-box{margin-top:22px;display:flex;align-items:center;gap:16px;background:var(--card-2);
  border:1.5px solid var(--line);border-radius:var(--r-field);padding:16px;}
.dark .qr-box{background:var(--card-2);border-color:var(--line);}
/* A QR has to stay black-on-white to scan, so it keeps its own white plate. */
.qr-box img{width:96px;height:96px;border-radius:12px;background:#fff;padding:6px;border:1px solid var(--line-2);}

/* ---------- Phone mock ---------- */
.phone-mock{width:290px;border-radius:44px;background:var(--black);border:6px solid var(--card-3);padding:14px 12px;
  box-shadow:var(--shadow-lg),0 0 0 1px rgba(255,255,255,.06) inset;position:relative;}
.phone-mock::before{content:"";position:absolute;top:16px;left:50%;transform:translateX(-50%);
  width:86px;height:20px;background:var(--black);border-radius:12px;z-index:3;}
.phone-screen{border-radius:32px;overflow:hidden;background:linear-gradient(170deg,var(--card-2),var(--black));
  aspect-ratio:9/17.5;position:relative;}
.phone-notch-bar{position:absolute;top:8px;left:14px;right:14px;display:flex;justify-content:space-between;
  font-size:.55rem;color:var(--tx-3);z-index:2;direction:ltr;}
.phone-logo{display:block;width:112px;height:42px;background:var(--lime);
  -webkit-mask:url("/assets/img/favicon.svg") no-repeat center/contain;
  mask:url("/assets/img/favicon.svg") no-repeat center/contain;}
.hero-scene{position:relative;aspect-ratio:21/9;border-radius:var(--r-card);overflow:hidden;
  background:linear-gradient(150deg,var(--card-2),var(--black));}
.hero-scene svg{position:absolute;inset:0;width:100%;height:100%;}
@keyframes floaty{0%,100%{transform:translateY(0);}50%{transform:translateY(-14px);}}
@keyframes pulsegold{0%,100%{opacity:.5;}50%{opacity:1;}}

/* ---------- Info list (detail pages) ---------- */
.info-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:14px;}
@media(max-width:768px){.info-grid{grid-template-columns:1fr;}}
.info-item{background:var(--card);border:1.5px solid var(--line);border-radius:var(--r-field);padding:18px 20px;}
.dark .info-item{background:var(--card);border-color:var(--line);}
.info-item small{display:block;font-size:var(--t-xs);color:var(--tx-3);font-weight:700;margin-bottom:4px;}
.dark .info-item small{color:var(--tx-3);}
.info-item b{font-size:1rem;color:var(--tx);}
.info-item .gold,.dark .info-item .gold{color:var(--lime);}

/* ---------- Teams registered ---------- */
.team-row{display:flex;align-items:center;gap:14px;background:var(--card);border:1.5px solid var(--line);
  border-radius:var(--r-field);padding:14px 18px;margin-bottom:10px;}
.dark .team-row{background:var(--card);border-color:var(--line);color:var(--tx-2);}
.team-row .avatar{width:40px;height:40px;font-size:var(--t-sm);}
.team-row b{display:block;line-height:1.3;color:var(--tx);}
.team-row small{color:var(--tx-3);font-size:var(--t-xs);}
.dark .team-row small{color:var(--tx-3);}
.team-row .paid-chip{margin-inline-start:auto;font-size:var(--t-xs);font-weight:800;padding:6px 12px;
  border-radius:var(--r-pill);background:var(--ok-bg);color:var(--ok);border:1px solid var(--ok-line);
  white-space:nowrap;}
/* Pending payment is a caution, not a prize. It takes --warn, the token
   .badge.warn already uses, so gold keeps meaning that something was won. */
.team-row .pend-chip{margin-inline-start:auto;font-size:var(--t-xs);font-weight:800;padding:6px 12px;
  border-radius:var(--r-pill);background:var(--warn-bg);color:var(--warn);border:1px solid var(--warn-line);
  white-space:nowrap;}

/* ---------- Prize cards ----------
   Prizes are the gold department. */
.prize-hero{border-radius:var(--r-card);overflow:hidden;
  background:linear-gradient(150deg,var(--card-2),var(--card));color:var(--tx-2);
  border:1.5px solid var(--gold-line);}
.prize-hero .eyebrow{color:var(--gold);}
.prize-rank{display:inline-flex;align-items:center;gap:8px;background:var(--gold);color:var(--gold-ink);
  font-weight:900;font-size:var(--t-sm);padding:8px 18px;border-radius:var(--r-pill);}
.prize-card{background:var(--card);border:1.5px solid var(--line);border-radius:var(--r-card);
  padding:28px;}
.dark .prize-card{background:var(--card);border-color:var(--line);}

/* ---------- Stepper ---------- */
.stepper{display:flex;align-items:center;gap:0;margin-bottom:32px;flex-wrap:wrap;}
.step{display:flex;align-items:center;gap:10px;font-size:var(--t-sm);font-weight:800;color:var(--tx-3);}
.step .dot{width:30px;height:30px;border-radius:var(--r-round);background:var(--card-2);color:var(--tx-2);
  border:1px solid var(--line-2);
  display:flex;align-items:center;justify-content:center;font-size:var(--t-xs);font-weight:900;flex-shrink:0;}
.step.active{color:var(--tx);}
.step.active .dot{background:var(--lime);color:var(--lime-ink);border-color:var(--lime);}
.step.done .dot{background:var(--ok);color:var(--ok-ink);border-color:var(--ok);}
.step-line{width:44px;height:2px;background:var(--line-2);margin-inline:10px;flex-shrink:0;}
/* The labels used to be dropped outright below this width, which left four
   numbered circles telling the visitor they are on step 1 of 4 without saying
   what the other three are. Sixty pixels bought at the cost of knowing where
   you are. They shrink now. */
@media(max-width:768px){.step span.lbl{font-size:var(--t-xs);} .step-line{width:20px;}}

/* ---------- Success page ---------- */
.success-icon{width:96px;height:96px;border-radius:var(--r-round);background:var(--ok);color:var(--ok-ink);
  display:flex;align-items:center;justify-content:center;margin:0 auto 26px;
  box-shadow:0 20px 46px -14px rgba(63,208,106,.5);animation:pop .6s var(--ease);}
@keyframes pop{0%{transform:scale(.4);opacity:0;}70%{transform:scale(1.12);}100%{transform:scale(1);opacity:1;}}
.reg-num-box{display:inline-flex;align-items:center;gap:12px;background:var(--lime-bg);
  border:1.5px dashed var(--lime);border-radius:var(--r-field);padding:14px 26px;
  font-weight:900;font-size:1.3rem;color:var(--lime);direction:ltr;letter-spacing:.06em;
  font-variant-numeric:tabular-nums;}

/* ---------- Payment ---------- */
.pay-summary{background:var(--card-2);border:1.5px solid var(--line);border-radius:var(--r-field);
  padding:18px 20px;margin-bottom:22px;}
.pay-badge{display:inline-flex;align-items:center;gap:8px;font-size:var(--t-xs);font-weight:800;
  padding:6px 12px;border-radius:var(--r-pill);background:var(--card-3);color:var(--tx-2);
  border:1px solid var(--line-2);}
.avatar--coach{background:var(--info)!important;color:var(--info-ink)!important;}
.card-visual{background:linear-gradient(140deg,var(--card-3),var(--card));border-radius:18px;padding:22px;
  color:var(--tx);margin-bottom:22px;position:relative;overflow:hidden;border:1px solid var(--line-2);}
.card-visual::before{content:"";position:absolute;inset:0;
  background-image:radial-gradient(rgba(232,252,44,.35) 1px,transparent 1.4px);
  background-size:20px 20px;opacity:.12;}
.card-visual .num{font-size:1.25rem;letter-spacing:.14em;direction:ltr;text-align:left;
  font-weight:700;margin-top:26px;position:relative;font-variant-numeric:tabular-nums;}
.card-visual .row{display:flex;justify-content:space-between;margin-top:16px;font-size:var(--t-xs);
  color:var(--tx-3);position:relative;}

/* ==========================================================================
   ADMIN - same identity, higher density. Nothing here is a second theme.
   ========================================================================== */
.admin-body{background:var(--bg);color:var(--tx-2);}
.admin-shell{display:grid;grid-template-columns:250px 1fr;min-height:100dvh;}
.admin-side{background:var(--surface);color:var(--tx-2);padding:26px 18px;position:sticky;top:0;height:100dvh;
  overflow-y:auto;display:flex;flex-direction:column;gap:4px;z-index:50;
  border-inline-end:1px solid var(--line);}
.admin-side .logo{margin-bottom:26px;padding-inline:8px;}
.admin-nav-btn{display:flex;align-items:center;gap:12px;padding:13px 16px;border-radius:12px;
  font-weight:700;font-size:var(--t-md);color:var(--tx-3);text-align:start;width:100%;
  transition:background var(--dur-micro) linear,color var(--dur-micro) linear;}
@media(hover:hover){
  .admin-nav-btn:hover{background:var(--card-2);color:var(--tx);}
}
.admin-nav-btn.active{background:var(--lime);color:var(--lime-ink);}
.admin-nav-btn:active{transform:scale(.985);}
.admin-nav-btn[disabled]{opacity:.45;pointer-events:none;}
.admin-nav-btn .ic{width:17px;height:17px;}
.admin-side .side-foot{margin-top:auto;padding-top:20px;border-top:1px solid var(--line);
  display:flex;flex-direction:column;gap:8px;}
.admin-main{padding:30px 34px 80px;min-width:0;}
.admin-top{display:flex;align-items:center;justify-content:space-between;gap:16px;
  margin-bottom:28px;flex-wrap:wrap;}
.admin-top h1{font-size:1.6rem;font-weight:900;color:var(--tx);}
.admin-card{background:var(--card);border:1.5px solid var(--line);border-radius:var(--r-card);
  padding:26px;margin-bottom:22px;}
.admin-card h3{margin-bottom:16px;display:flex;align-items:center;gap:10px;}
.a-table{width:100%;border-collapse:collapse;font-size:var(--t-sm);}
.a-table th{background:var(--card-3);color:var(--tx-2);font-size:var(--t-xs);font-weight:800;
  padding:12px 14px;text-align:start;white-space:nowrap;}
.a-table td{padding:12px 14px;border-bottom:1px solid var(--line);vertical-align:middle;
  font-variant-numeric:tabular-nums;}
.a-table tr:last-child td{border-bottom:none;}
@media(hover:hover){
  .a-table tr:hover td{background:var(--card-2);}
}
.badge{display:inline-flex;align-items:center;gap:6px;font-size:var(--t-xs);font-weight:800;
  padding:5px 12px;border-radius:var(--r-pill);white-space:nowrap;border:1px solid transparent;}
.badge.green{background:var(--ok-bg);color:var(--ok);border-color:var(--ok-line);}
.badge.gold,.badge.warn{background:var(--warn-bg);color:var(--warn);border-color:var(--warn-line);}
.badge.navy{background:var(--lime-bg);color:var(--lime);border-color:var(--lime-line);}
.badge.purple{background:var(--info-bg);color:var(--info-tx);border-color:var(--info-line);}
.badge.red{background:var(--danger-bg);color:var(--danger);border-color:var(--danger-line);}
.badge.gray{background:var(--card-3);color:var(--tx-3);border-color:var(--line-2);}
.icon-btn{width:34px;height:34px;border-radius:10px;outline-offset:2px;background:var(--card-2);display:inline-flex;
  align-items:center;justify-content:center;color:var(--tx-2);border:1px solid var(--line-ctl);
  transition:background var(--dur-micro) linear,color var(--dur-micro) linear,border-color var(--dur-micro) linear;}
@media(hover:hover){
  .icon-btn:hover{background:var(--lime);color:var(--lime-ink);border-color:var(--lime);}
}
@media(hover:hover){
  .icon-btn.danger:hover{background:var(--danger);color:var(--danger-ink);border-color:var(--danger);}
}
.icon-btn:active{transform:scale(.92);}
.icon-btn[disabled]{opacity:.45;pointer-events:none;}
.admin-grid-2{display:grid;grid-template-columns:1fr 1fr;gap:18px;}
@media(max-width:1180px){
  .admin-shell{grid-template-columns:1fr;}
  .admin-side{position:static;height:auto;flex-direction:row;flex-wrap:wrap;align-items:center;
    border-inline-end:none;border-bottom:1px solid var(--line);}
  .admin-side .logo{margin-bottom:8px;}
  .admin-nav-btn{width:auto;}
  .admin-side .side-foot{margin-top:0;border:none;flex-direction:row;padding-top:0;}
}
@media(max-width:768px){.admin-grid-2{grid-template-columns:1fr;} .admin-main{padding:20px 16px 60px;}}
.admin-login{min-height:100dvh;display:flex;align-items:center;justify-content:center;
  background:var(--bg);position:relative;overflow:hidden;padding:20px;}

@media print{
  .site-header,.site-footer,.no-print,.toast-zone{display:none!important;}
  /* Print is ink on paper, so the identity inverts once, deliberately. */
  body{background:#fff;color:#111;}
  .print-sheet{box-shadow:none!important;border:none!important;}
}

/* ---------- Inline links in body copy ----------
   Without this every inline <a> inside a card or a prose block has to declare
   its own colour, and a missed one inherits the body ramp and disappears. */
.card a:not([class]),.panel-dark a:not([class]),.prize-card a:not([class]),
.summary-list a:not([class]),.acc-panel-inner a:not([class]),
.info-item a:not([class]),.match-card a:not([class]),.t-body a:not([class]),
.c-content a:not([class]),.form-card a:not([class]),.prose a:not([class]){
  color:var(--lime);text-underline-offset:3px;
  transition:color var(--dur-micro) linear;}
.card a:not([class]):hover,.panel-dark a:not([class]):hover,
.prize-card a:not([class]):hover,.summary-list a:not([class]):hover,
.acc-panel-inner a:not([class]):hover,.info-item a:not([class]):hover,
.match-card a:not([class]):hover,.t-body a:not([class]):hover,
.c-content a:not([class]):hover,.form-card a:not([class]):hover,
@media(hover:hover){
  .prose a:not([class]):hover{color:var(--lime-hi);text-decoration:underline;}
}

/* ---------- Small helpers ---------- */
.empty-note{padding:40px;text-align:center;color:var(--tx-3);background:var(--card);
  border:1.5px dashed var(--line-2);border-radius:var(--r-field);font-weight:700;}
.dark .empty-note{background:var(--card);border-color:var(--line-2);color:var(--tx-3);}
.count-live{display:inline-flex;align-items:center;gap:8px;font-weight:900;font-variant-numeric:tabular-nums;}
.count-live .pulse{width:9px;height:9px;border-radius:var(--r-round);background:var(--lime);
  animation:pulsegold 1.6s infinite;}
@media(hover:hover){
  .play-fab:hover{background:var(--lime)!important;color:var(--lime-ink)!important;transform:scale(1.08);}
}
/* The WhatsApp float is drawn with inline styles by ui.js because it is
   appended to every page, so its keyboard state has to live here. The green
   and the white glyph are WhatsApp's trademark and are left untouched; only
   the ring around them is ours. */
.wa-float:focus-visible{outline:2.5px solid var(--lime);outline-offset:3px;}
.wa-float:active{transform:scale(.96);}
/* ui.js sets this while a button or link is underneath the float. */
.wa-float.is-yielding{opacity:0;pointer-events:none;transform:scale(.8)!important;}
.play-fab:focus-visible{outline:2.5px solid var(--lime);outline-offset:3px;}

/* Footer and inline text links are tap targets too. */
.footer-col a,.footer-social a,.crumbs a{display:inline-flex;align-items:center;min-height:var(--tap);}
.footer-social a{justify-content:center;min-width:var(--tap);}

/* ---------- Third-party artwork that cannot be recoloured ----------
   The App Store badge, partner logos and the QR are supplied as dark-on-light
   artwork. Inverting them would break a trademark or stop a scan, so each
   keeps a light plate of its own and the plate is what sits on the ground. */
.on-light-plate{background:var(--white);border-radius:10px;padding:6px 10px;}
/* A partner mark dropped into a media frame would otherwise be cropped by
   `.c-media img`'s cover fill, and its plate would flood the whole tile. It
   floats inside the frame instead, contained and never recoloured. */
.c-media img.on-light-plate,.t-poster img.on-light-plate{
  inset:16px;width:auto;height:auto;max-width:calc(100% - 32px);max-height:calc(100% - 32px);
  margin:auto;object-fit:contain;padding:14px;border-radius:14px;}

/* An uploaded logo fits the box it is given: scaled up or down until it
   meets the box on one side, never stretched and never cropped. Every logo
   slot used `max-height` with `width:auto`, which can only shrink an image,
   so a small file sat small in a large frame; the partner page capped its
   mark at 1.6rem inside a 118px square.

   Until the image has loaded, or with no script, the element fills the box
   with `object-fit:contain`, which already never distorts. ui.js then sizes
   the element itself to the fitted rectangle, so the light plate behind a
   logo hugs the artwork instead of flooding the whole frame white. */
/* Fit means edge to edge: the image grows until it touches the box on one
   side. The boxes carried 12-16px and even 9-11% of padding, and the plate
   added its own on top, so an upload stopped well short of the edges and
   wore a white frame. The plate is kept only as a background: invisible
   behind an opaque picture, still there behind a transparent dark logo. */
.logo-box{display:flex;align-items:center;justify-content:center;padding:0;overflow:hidden;}
.logo-box img.logo-fit{position:relative;inset:auto;margin:0;flex:none;display:block;
  width:100%;height:100%;max-width:none;max-height:none;object-fit:contain;
  padding:0;border-radius:var(--r-field);}

/* Every logo slot is square. Uploads are mostly square or near-square, and
   a wide slot left most of it empty on either side of the picture. The
   sponsor cards on the sponsors page share `.c-media` with courts, so the square is its own modifier rather than a change to
   the shared frame. */
.c-media--square{aspect-ratio:1 / 1;}

/* ---------- Sponsor network grid ----------
   Grid rows size themselves one at a time, so the row holding the longest
   sponsor name stood 384px tall and the row below it 364px — a 20px step in
   the middle of a wall of logos. One row height for the whole grid, taken
   from the tallest card in it, and every card fills the row it is in. */
.logo-grid{grid-auto-rows:1fr;}
.logo-grid > .c-card{height:100%;}

/* A sponsor with no uploaded logo used to print its name twice: once set
   large inside the logo plate and once again in the caption under it. The
   plate now carries a monogram — the sponsor's own initials, drawn as a
   mark, which is what the plate is for — and the name is read once, in the
   caption, where every other card carries it too. */
.c-mono{position:relative;z-index:1;display:flex;align-items:center;justify-content:center;
  inline-size:46%;block-size:46%;border-radius:var(--r-card);
  background:linear-gradient(150deg,rgba(232,252,44,.16),rgba(232,252,44,.04));
  border:1.5px solid rgba(232,252,44,.28);
  font-weight:900;font-size:clamp(1.3rem,4.4vw,1.9rem);letter-spacing:.02em;
  color:var(--lime);line-height:1;}

/* A supplied logo is artwork we do not own and cannot recolour, so the plate
   behind it exists for exactly one case: a transparent mark drawn in dark
   ink, which would otherwise disappear into a black card. An opaque picture
   brings its own background and a light transparent mark needs none — both
   were being pasted onto a white rectangle that filled the tile and read as
   a slab. sponsors.html measures the file once it has loaded and sets this
   class only on the marks that actually need the plate. Scoped to this grid:
   the partner tiles elsewhere keep the plate they were given. */
.logo-grid img.logo-fit{background:transparent;}
.logo-grid img.logo-fit.needs-plate{background:var(--white);}
/* Whatever the file turns out to be, the mark sits clear of the tile's edges
   with a corner of its own. A logo supplied as an opaque picture still brings
   its own white with it — that is the artwork, and recolouring a trademark is
   not ours to do — but held off the edges it reads as a plate laid on the
   card, the way a brand mark is presented, instead of the tile itself turning
   white from edge to edge. */
.logo-grid .c-media{padding:clamp(14px,4.5%,22px);}
.logo-grid img.logo-fit{border-radius:12px;}

/* The partner block on the sponsors page sits in half of a two-column card,
   and that cell's height comes from the copy beside it. The logo is a square
   as tall as the cell, 24px clear of its edges, so the card keeps its height:
   the cell is stretched by the grid, which makes its height definite, and
   the square takes its width from that height. (Container query units were
   tried first and resolved to zero in the stacked phone layout.) */
.logo-cell{display:flex;align-items:center;justify-content:center;padding:24px;}
/* Capped at the same 460px as the homepage partner tile, so the two match and
   a wide desktop cell does not grow the card far past the copy beside it. */
.logo-cell > #ptLogo{position:relative;height:100%;width:auto;aspect-ratio:1 / 1;max-width:min(100%, 460px);}

/* ---------- Wide tournament card ----------
   One tournament on its own used to sit in a third of a row of empty page,
   because .grid-3 keeps three columns whatever it is given. The wide variant
   turns the same card on its side instead, so a single card fills the row it
   is in rather than shrinking away from it. */
.t-card--wide{flex-direction:row;align-items:stretch;}
.t-card--wide .t-poster{flex:0 0 46%;aspect-ratio:auto;min-height:360px;}
.t-card--wide .t-body{padding:clamp(26px,3.4vw,44px);justify-content:center;}
.t-card--wide .t-actions{flex:0 0 auto;}
.t-card--wide .t-actions .btn{flex:0 1 auto;}
@media(max-width:900px){
  .t-card--wide{flex-direction:column;}
  .t-card--wide .t-poster{flex:none;aspect-ratio:16/9;min-height:0;}
  .t-card--wide .t-actions .btn{flex:1 1 100%;}
}
