/* =============================================================================
   hero.css — the pinned "portal" hero the user scroll-flies through
   ----------------------------------------------------------------------------
   Layer order inside #hero (low -> high):
     .hero__canvas   (--z-three : 0)   fixed WebGL glass blocks (opacity 0 until 3D inits)
     .portal         (--z-portal: 50)  the scaling brand square + motif pattern
     .hero__content  (--z-base  : 1)   title / cta / scroll cue   (sits ABOVE three, BELOW portal? no)
   NOTE: portal sits above content on purpose so the square can wipe across the
   text as we "exit" the portal; content fades out (Phase A) before the square
   grows large enough to cover it, so reading order is preserved.
   portal.js owns the scroll timeline; this file only styles the resting scene
   and the reduced-motion / no-WebGL fallbacks.
   ========================================================================== */

/* generic helper for any pinned trigger section */
.section--pinned {
  position: relative;
}

.hero {
  position: relative;
  min-height: 100vh;          /* fallback */
  min-height: 100svh;         /* mobile-safe */
  overflow: clip;
  /* matches the page background so the pin transition is seamless */
  background-color: var(--surface-bg);
  isolation: isolate;         /* keep our z-index scale self-contained */
}

/* Soft ambient brand glow behind the content at rest — gives warmth & depth
   WITHOUT a hard block competing with the headline. Sits above the canvas,
   below the portal + content. */
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    radial-gradient(40% 46% at 50% 40%,
      color-mix(in srgb, var(--brand-secondary) 24%, transparent) 0%,
      transparent 66%),
    radial-gradient(58% 64% at 50% 58%,
      color-mix(in srgb, var(--brand-primary) 13%, transparent) 0%,
      transparent 72%);
}
/* in dark (charcoal) the brand glow is dialled WAY back so the hero reads as
   the same neutral charcoal as every other section (just a faint warmth). */
[data-theme="dark"] .hero::before { opacity: 0.32; }

/* =============================================================================
   WEBGL CANVAS — fixed full-bleed, behind everything, faded in by three-hero.js
   ========================================================================== */
.hero__canvas {
  position: fixed;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  z-index: var(--z-three);
  pointer-events: none;
  opacity: 0;                 /* three-hero.js sets to 1 on first frame; stays 0 if no 3D */
  transition: opacity 1.1s var(--ease-cinematic, ease);
  /* hint compositor without forcing a layer permanently */
  will-change: opacity;
}

/* =============================================================================
   THE PORTAL — the scaling brand square + the motif pattern behind it
   ========================================================================== */
.portal {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  z-index: var(--z-portal);
  pointer-events: none;
}

/* The motif sits behind the square; fades out as we fly in (portal.js drives). */
.portal__pattern {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: .12;               /* base subtle presence; JS fades to 0 */
  /* .motif-bg (motif.css) supplies the tiled image + radial mask */
}

/* The hero square — "the centre block" — scales ~22x through the viewport.
   Base size min(42vw,42vh): at any aspect ratio (incl. 21:9), base * 22 covers
   the viewport with huge margin (42vh*22 = 924vh >> 100vw even at 21:9). */
.portal__square {
  position: relative;
  z-index: 1;
  opacity: 0;                 /* hidden at rest — portal.js fades it in as you scroll */
  inline-size: min(42vw, 42vh);
  block-size: min(42vw, 42vh);
  aspect-ratio: 1 / 1;
  border-radius: var(--radius-block);
  /* fly INTO a real Prime Schools scene, tinted with the brand gradient so it
     stays cohesive. To swap: change the image url below (any file in
     assets/img/gallery/), or delete this block to fall back to the gradient. */
  background-color: var(--mark-c, var(--c-pink));
  background-image:
    linear-gradient(135deg,
      color-mix(in srgb, var(--brand-primary) 38%, transparent),
      color-mix(in srgb, var(--brand-primary) 12%, transparent) 70%),
    image-set(
      url("../assets/img/hero/campus.webp") type("image/webp"),
      url("../assets/img/hero/campus.jpg") type("image/jpeg"));
  background-size: cover;
  background-position: center;
  /* Lighter shadow: this square scales up to 6×, and box-shadows scale with it,
     so the old big blurs (60px/80px) became huge and forced expensive re-rasters
     every frame (measured 200–750ms stalls scrolling up). A single small inset
     glow keeps a touch of depth but is cheap to raster while flying. The outer
     bloom was dropped — it's invisible once the square fills the screen anyway. */
  box-shadow: inset 0 0 20px color-mix(in srgb, var(--c-white) 26%, transparent);
  transform-origin: center center;
  will-change: transform;
  /* keep edges crisp through massive upscaling */
  backface-visibility: hidden;
}

/* a brighter specular core so the "inner glow" survives the upscale */
.portal__square::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(
    120% 120% at 32% 28%,
    color-mix(in srgb, var(--c-white) 26%, transparent) 0%,
    transparent 50%
  );
  pointer-events: none;
}

/* =============================================================================
   FALLBACK SCENE (no WebGL) — portal.js .fallbackToLite() adds .hero--lite.
   A brand gradient (and optional gallery image) behind the portal so the
   fly-through still looks rich without Three. Image is OPTIONAL — if missing,
   the gradient alone carries it (no broken-image box; background-image only).
   ========================================================================== */
.hero--lite .portal {
  background:
    radial-gradient(60% 60% at 50% 38%,
      color-mix(in srgb, var(--brand-secondary) 26%, transparent),
      transparent 70%),
    linear-gradient(160deg,
      color-mix(in srgb, var(--brand-primary) 16%, var(--surface-bg)),
      var(--surface-bg) 60%);
}

/* If the optional scene image exists it layers on top of the gradient; a
   missing file simply yields no extra layer (background-image never shows
   a broken-image icon). portal.js toggles .hero--lite-img once it preloads. */
.hero--lite-img .portal {
  background-image:
    radial-gradient(60% 60% at 50% 38%,
      color-mix(in srgb, var(--brand-secondary) 22%, transparent),
      transparent 72%),
    image-set(url("../assets/img/gallery/scene-01.jpg") 1x);
  background-size: cover, cover;
  background-position: center, center;
}

/* =============================================================================
   HERO CONTENT — eyebrow / title / subtitle / cta / scroll cue
   ========================================================================== */
.hero__content {
  position: relative;
  z-index: 60;                /* above the portal + ambient glow */
  min-height: inherit;
  width: min(92vw, var(--container));
  margin-inline: auto;
  padding-block: calc(var(--space-9) + var(--space-4)) var(--space-8);
}

/* split: live text on one side, campus image on the other, vertically centred */
.hero__content--split {
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  align-items: center;
  gap: clamp(1.5rem, 4vw, 4rem);
}

.hero__text {
  display: grid;
  justify-items: start;
  gap: var(--space-4);
  text-align: start;
}

.hero__eyebrow {
  margin: 0;
  font-size: clamp(.78rem, 1.6vw, .92rem);
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--brand-primary);
}
:where(html[lang="ar"], .lang-ar) .hero__eyebrow {
  text-transform: none;
  letter-spacing: .04em;
}

.hero__title {
  margin: 0;
  display: grid;
  gap: .08em;
  font-size: clamp(2rem, 4.6vw, 3.6rem);
  /* the brand Arabic face has deep descenders (ي/ج/ص/ق); a tight line-height
     let them fall outside the clipped-text background box and get cut off */
  line-height: 1.28;
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--text-primary);
  text-wrap: balance;
}
/* the second line punches in the brand gradient. background-clip:text only
   paints where the gradient box overlaps the glyphs — pad the block-end so the
   gradient extends below the baseline and the Arabic descenders aren't clipped. */
.hero__title-accent {
  background: var(--gradient-brand);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  padding-block-end: 0.18em;
}
/* Forced-colors / Windows High-Contrast: clipped-to-text gradient renders as
   invisible (transparent) text — restore a solid system color so the headline
   never disappears. */
@media (forced-colors: active) {
  .hero__title-accent {
    -webkit-text-fill-color: currentColor;
    color: currentColor;
    background: none;
  }
}

.hero__body {
  margin: 0;
  font-size: clamp(1rem, 1.4vw, 1.16rem);
  font-weight: 500;
  line-height: 1.7;
  color: var(--text-muted);
  max-width: 46ch;
}

/* feature pills (2×2) */
.hero__features {
  list-style: none;
  margin: var(--space-2) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-3) var(--space-5);
  width: 100%;
  max-width: 30rem;
}
.hero__feature {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  font-weight: 600;
  color: var(--text-primary);
}
.hero__feature-ic {
  display: inline-grid;
  place-items: center;
  inline-size: 40px;
  block-size: 40px;
  flex: 0 0 auto;
  border-radius: 12px;
  color: var(--brand-primary);
  background: color-mix(in srgb, var(--brand-primary) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--brand-primary) 22%, transparent);
}
.hero__feature-ic svg { inline-size: 21px; block-size: 21px; }

.hero__cta-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-block-start: var(--space-3);
}
.hero__cta { margin: 0; }

/* campus image panel */
.hero__media {
  position: relative;
  justify-self: stretch;
}
.hero__img {
  display: block;
  inline-size: 100%;
  block-size: min(62vh, 30rem);
  object-fit: cover;
  border-radius: var(--radius-xl);
  border: 1px solid var(--glass-border);
  box-shadow: 0 30px 70px color-mix(in srgb, var(--brand-primary) 26%, transparent);
}

/* ---------- SCROLL CUE (pinned near bottom-centre) ---------- */
.hero__scroll-cue {
  position: absolute;
  inset-block-end: clamp(1.25rem, 4vh, 2.5rem);
  inset-inline: 0;
  margin-inline: auto;
  width: max-content;
  display: grid;
  justify-items: center;
  gap: var(--space-2);
  font-size: .8rem;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--text-muted);
  pointer-events: none;
}

:where(html[lang="ar"], .lang-ar) .hero__scroll-cue {
  text-transform: none;
  letter-spacing: .04em;
}

.hero__chevron {
  inline-size: 14px;
  block-size: 14px;
  /* PHYSICAL borders: a down-arrow is identical in LTR & RTL. Using logical
     border-inline-end flips to the LEFT border in RTL, which rotated the
     chevron sideways instead of pointing down. */
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg);
  animation: ps-hero-chevron 1.8s var(--ease-out, ease-in-out) infinite;
}

@keyframes ps-hero-chevron {
  0%   { transform: translateY(-3px) rotate(45deg); opacity: .35; }
  50%  { transform: translateY(3px)  rotate(45deg); opacity: 1; }
  100% { transform: translateY(-3px) rotate(45deg); opacity: .35; }
}

/* =============================================================================
   RESPONSIVE — stack the split hero on small screens (compact so it fits ~100svh)
   ========================================================================== */
@media (max-width: 900px) {
  .hero__content {
    padding-block: calc(var(--space-8) + var(--space-4)) var(--space-6);
  }
  .hero__content--split {
    grid-template-columns: 1fr;
    gap: var(--space-4);
  }
  .hero__text { justify-items: center; text-align: center; gap: var(--space-3); }
  .hero__body { margin-inline: auto; }
  .hero__features { margin-inline: auto; max-width: 24rem; }
  .hero__cta-row { justify-content: center; }
  .hero__title { font-size: clamp(1.9rem, 7.5vw, 2.8rem); }
  .hero__img { block-size: min(34vh, 14rem); }
}

@media (max-width: 560px) {
  .hero__body { font-size: .98rem; line-height: 1.6; }
  .hero__features { gap: var(--space-2) var(--space-3); max-width: 21rem; }
  .hero__feature { gap: var(--space-2); font-size: .92rem; }
  .hero__feature-ic { inline-size: 34px; block-size: 34px; }
  .hero__feature-ic svg { inline-size: 18px; block-size: 18px; }
  .hero__img { block-size: min(28vh, 11rem); }
}

/* =============================================================================
   REDUCED MOTION — no pinning happens (portal.js returns early). Present a
   clean, readable static hero: hide the scaling square + canvas, stop the
   chevron bounce, keep content centred and fully visible.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .hero__chevron { animation: none; transform: rotate(45deg); }
  .portal__square { display: none; }
  .portal__pattern { opacity: .08; }
  .hero__canvas { display: none; }
}

/* =============================================================================
   MEDIA HERO (client request) — full-bleed school-photo slideshow (crossfade +
   slow Ken-Burns zoom) under a brand overlay, with centred white content.
   Replaces the pinned "portal" hero (portal.js returns early: no .section--pinned).
   ========================================================================== */
.hero--media {
  display: grid;
  place-items: center;
  text-align: center;
  overflow: hidden;
  background-color: var(--c-navy);   /* base while the first photo decodes */
}
.hero--media::before { display: none; }   /* drop the light ambient glow */

/* the crossfading slides */
.hero__slideshow { position: absolute; inset: 0; z-index: 0; }
.hero__slide {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  opacity: 0;
  will-change: opacity, transform;
  /* 6 slides × 8s each = 48s loop */
  animation: heroSlideKen 48s linear infinite;
}
.hero__slide:nth-child(1) { animation-delay: 0s; }
.hero__slide:nth-child(2) { animation-delay: 8s; }
.hero__slide:nth-child(3) { animation-delay: 16s; }
.hero__slide:nth-child(4) { animation-delay: 24s; }
.hero__slide:nth-child(5) { animation-delay: 32s; }
.hero__slide:nth-child(6) { animation-delay: 40s; }
/* percentages keep the same real timing as before: ~1s fade-in, visible to ~7s,
   fully out by 8s (8s / 48s = 16.7%) */
@keyframes heroSlideKen {
  0%     { opacity: 0; transform: scale(1.12); }
  2%     { opacity: 1; }
  14.7%  { opacity: 1; }
  16.7%  { opacity: 0; }
  100%   { opacity: 0; transform: scale(1.0); }
}

/* brand overlay for text legibility */
.hero__overlay {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    linear-gradient(180deg,
      color-mix(in srgb, var(--c-dpurple) 60%, transparent) 0%,
      color-mix(in srgb, var(--c-dpurple) 46%, transparent) 42%,
      color-mix(in srgb, var(--c-navy) 82%, transparent) 100%);
}

/* content sits over the imagery, centred, white */
.hero--media .hero__content {
  position: relative;
  z-index: 3;
  min-height: auto;
  display: grid;
  justify-items: center;
  gap: var(--space-4);
  max-width: 60rem;
  padding-block: calc(var(--space-9) + var(--space-4)) var(--space-9);
  color: #fff;
}
/* client: eyebrow + title read as WHITE on the photo (yellow was unclear) */
.hero--media .hero__eyebrow { color: #fff; text-shadow: 0 2px 12px rgba(0, 0, 0, .45); }
.hero--media .hero__title {
  color: #fff;
  font-size: clamp(2.2rem, 5.2vw, 4rem);
  text-shadow: 0 2px 20px rgba(0, 0, 0, .55), 0 1px 3px rgba(0, 0, 0, .4);
}
/* hero brand logo (replaces the title text — client edit #4).
   Colour logo sits directly on the photo; a soft shadow lifts it off the
   background so it stays legible over any slide. */
.hero__logo-wrap { margin: 0; line-height: 0; }
.hero__logo {
  display: block;
  margin-inline: auto;
  inline-size: clamp(230px, 30vw, 340px);
  block-size: auto;
  filter: drop-shadow(0 6px 22px rgba(0, 0, 0, .35));
}
@media (max-width: 560px) { .hero__logo { inline-size: clamp(200px, 62vw, 280px); } }
.hero--media .hero__title-accent {
  background: none;
  -webkit-text-fill-color: var(--c-pink);
  color: var(--c-pink);
}
.hero--media .hero__body {
  color: rgba(255, 255, 255, .92);
  max-width: 52ch;
  margin-inline: auto;
  font-size: clamp(1rem, 1.5vw, 1.2rem);
}
.hero--media .hero__features {
  margin-inline: auto;
  max-width: 90vw;
  grid-template-columns: repeat(2, max-content);
  justify-content: center;   /* centre the 2-column group */
  justify-items: start;      /* pills hug column start → icons align */
  column-gap: var(--space-6);
}
.hero--media .hero__feature { justify-content: flex-start; }
.hero--media .hero__feature { color: #fff; }
.hero--media .hero__feature-ic {
  color: #fff;
  background: rgba(255, 255, 255, .15);
  border-color: rgba(255, 255, 255, .3);
}
.hero--media .hero__cta-row { justify-content: center; }
.hero--media .hero__scroll-cue { color: rgba(255, 255, 255, .85); }

@media (max-width: 560px) {
  .hero--media .hero__content { padding-inline: var(--space-4); }
  .hero--media .hero__features { max-width: 100%; column-gap: var(--space-3); }
  .hero--media .hero__feature { gap: var(--space-2); }
}

@media (prefers-reduced-motion: reduce) {
  .hero__slide { animation: none; transform: none; }
  .hero__slide:nth-child(1) { opacity: 1; }
}
