/* Whitestone Juniors — reset, typography, layout primitives */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* The canvas colour, which is what macOS elastic overscroll reveals above the
     hero and below the footer. Left transparent it fell through to body's
     --paper and flashed an off-white bar at the top of the page. Both ends of
     the document are navy, so the canvas is navy. */
  background: var(--navy-deep);
}
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-text);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  letter-spacing: var(--ls-body);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img, picture, video, svg { display: block; max-width: 100%; }
img { height: auto; }

h1, h2, h3 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  text-transform: uppercase;
}
h1 { font-size: var(--fs-display); line-height: var(--lh-display); letter-spacing: var(--ls-display); }
h2 { font-size: var(--fs-h2);      line-height: var(--lh-h2);      letter-spacing: var(--ls-display); }
h3 { font-size: var(--fs-h3);      line-height: var(--lh-h3);      letter-spacing: -0.01em; font-family: var(--font-text); font-weight: 700; text-transform: none; }

p { margin: 0; }
a { color: inherit; }

/* ---------- Layout ---------- */

.section {
  position: relative;
  padding-block: var(--space-section);
  padding-inline: var(--gutter);
  background: var(--paper);
  color: var(--ink);
}
.section--flush { padding-block: 0; padding-inline: 0; }

/* Anchor targets clear the floating header pill (--header-top 12 + --header-h
   56, plus air). Only mattered once the menu made anchor jumps a primary way
   to move around: before that the only anchors were Join buttons landing on a
   vertically-centred card.

   #fridays is deliberately absent. Where that anchor lands is the panel wipe's
   business — §3's top IS §2's bottom, so stopping 88px short of it puts 88px
   of the navy band back on screen, which is the one thing that whole sequence
   exists to prevent. Its own section padding already clears the pill. */
#parents, #pendiri, #faq, #says { scroll-margin-top: 88px; }

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

/* ---------- Type helpers ---------- */

.micro {
  font-size: var(--fs-micro);
  line-height: 1.2;
  letter-spacing: var(--ls-micro);
  text-transform: uppercase;
  font-weight: 600;
  color: var(--ink-70);
}
.lead  { font-size: var(--fs-lead); color: var(--ink-70); }
.small { font-size: var(--fs-small); color: var(--ink-70); }

.section__head { margin-bottom: var(--space-8); }
.section__head .micro { display: block; margin-bottom: var(--space-3); }
.section__head p { margin-top: var(--space-4); max-width: 54ch; }

/* ---------- Accessibility ---------- */

/* The focus ring used to be --volt everywhere. Volt against --paper is 1.04:1 —
   the ring was effectively invisible on the whole light half of the page (header
   pill, act cards, terms). WCAG 1.4.11 wants 3:1 on a focus indicator, so the
   colour now follows the surface: navy on paper (17.5:1), volt on navy and over
   dark media (13.2:1). */
:focus-visible {
  outline: 3px solid var(--navy);
  outline-offset: 3px;
  border-radius: var(--radius-s);
}
.band--navy :focus-visible,
.on-media :focus-visible,
.header.is-inverted :focus-visible { outline-color: var(--volt); }

/* The two fixed volt pills float over BOTH halves of the page, so no single
   outside ring colour survives the scroll. Ring them on the inside instead —
   navy on volt is 13.2:1 regardless of what is passing behind. */
.skip-link:focus-visible,
.float-join:focus-visible {
  outline: 3px solid var(--navy);
  outline-offset: -6px;
}

.skip-link {
  position: absolute; left: var(--gutter); top: -100px; z-index: 100;
  background: var(--volt); color: var(--navy);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-s); font-weight: 700;
  transition: top var(--dur-ui) var(--ease-material);
}
.skip-link:focus { top: var(--space-3); }

.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---------- Reveal (paired with main.js) ----------
   Content is VISIBLE by default. main.js adds .has-reveal to <html> only once
   GSAP + ScrollTrigger have actually loaded and reduced-motion is off. If the
   CDN fails, the JS errors, or a crawler renders without scripts, the page
   still shows everything — hiding content behind JS that may not arrive is a
   defect, not a flourish. */

.has-reveal [data-reveal] {
  opacity: 0;
  transform: translateY(24px);
  will-change: transform, opacity;
}

/* Blur-to-focus. Desktop only: a blur animating on a mid-range Android is
   exactly the frame cost this build is supposed to avoid, so below 768px
   everything falls back to the plain opacity + y reveal.

   Two strengths, not one. 8px is the body default — enough to read as coming
   into focus, light enough that small text does not turn to mush on the way.
   The section heads keep 14px and their longer 0.85s (main.js), so the reveal
   carries the same hierarchy the type does instead of hitting everything at
   equal weight. */
@media (min-width: 768px) {
  .has-reveal [data-reveal] {
    filter: blur(8px);
    will-change: transform, opacity, filter;
  }
  .has-reveal [data-reveal="blur"] {
    filter: blur(14px);
  }
}

/* ---------- Word reveals (paired with js/words.js) ----------
   The box is the mask; the inner span is the only thing that moves. Both are
   inserted by JS, so this styles nothing until a splitter has run — no-JS and
   reduced-motion pages never see these classes at all.

   padding-bottom gives the descenders somewhere to be: a mask cropped to the
   text box shears the tail off every j, y and p, and "Padel juniors, every
   Friday" has two. The matching negative margin takes that padding straight
   back out of the line box, so splitting a heading does not move it. */

.wsplit {
  display: inline-block;
  overflow: hidden;
  /* Not baseline. An inline-block with overflow != visible takes its bottom
     margin edge as its baseline, which after the negative margin above lands
     ~0.14em off — invisible while every word in the line is wrapped, obvious
     the moment one is not (a .slot chip, an <a>, punctuation left as text).
     Aligning the boxes to each other instead removes the question. */
  vertical-align: bottom;
  padding-bottom: 0.14em;
  margin-bottom: -0.14em;
}

.wsplit__i { display: inline-block; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  [data-reveal] { opacity: 1 !important; transform: none !important; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}
