/* ============================================================
   MBZ — intro (فيديو مقدمة MBZ)
   A 21.5s composition authored at a fixed 1920x1080, ported by hand from
   the Claude Design prototype. This file holds the STATIC half of every
   layer; intro.js writes the moving half (opacity, transform, dash
   offsets, colours) once per frame from one clock.
   Nothing here animates on its own — no CSS transitions or keyframes on
   any composition layer — because the piece renders from T only. A frozen
   clock has to mean a genuinely frozen frame.
   ============================================================ */

* { box-sizing: border-box; }

/* overscroll: every screen here is a full-bleed layer that cannot scroll,
   and a downward drag on one would otherwise be Android's pull-to-refresh —
   the whole journey lost to a swipe. */
html, body { margin: 0; padding: 0; overscroll-behavior-y: none; }

body {
  background: #050505;
  color: #efece5;
  font-family: 'Almarai', sans-serif;
}

/* The stage is pinned to the viewport rather than merely min-height'd:
   #comp is a real 1080px-tall box that CSS transforms only *paint*
   smaller, so an auto-height stage would grow to 1080px and hand the
   visitor a scrollbar over a full-bleed film. min-height keeps the
   authored intent, height + overflow enforce it. */
#stage {
  position: relative;
  min-height: 100vh;
  height: 100vh;
  overflow: hidden;
  background: #050505;
}
@supports (height: 100dvh) {
  /* mobile browser chrome shrinks the visual viewport mid-scroll; dvh
     keeps the letterbox honest instead of cropping the frame */
  #stage { min-height: 100dvh; height: 100dvh; }
}
#stage:focus { outline: none; }

/* Touch hygiene. No image here is a click target (the handlers sit on the
   gate, the JOURNEY box and the credit), so a long press must not open the
   image sheet and a slightly moving press must not start a ghost drag —
   both silently ate the tap that opens the gate. manipulation keeps pinch
   zoom and removes double-tap zoom, which panned the fixed layers. */
#gate, #stage { -webkit-touch-callout: none; -webkit-user-select: none; user-select: none; }
#gate img, #stage img { -webkit-user-drag: none; pointer-events: none; }
#gate, #enter, #credit { touch-action: manipulation; }

/* Centred absolutely, not with flex: Chromium lets an oversized flex child
   hang off both edges of a centering container, but Safari pins it to the
   start edge instead — on iPhones the whole film slid sideways and showed
   the wrong slice. translate(-50%,-50%) is deterministic in every engine;
   intro.js appends the scale to the same transform. */
#comp {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 1920px;
  height: 1080px;
  transform: translate(-50%, -50%);
  transform-origin: center;
  overflow: hidden;
  background: #050505;
  font-family: 'Almarai', sans-serif;
}

/* ---------- 1-3. the three drifting canvases ---------- */
/* All three wander the frame on the same slow 0.06 rad/s circle, offset
   by a third of a turn each. They are fed T + idle, so they keep living
   after the composition freezes. */

.drift {
  position: absolute;
  pointer-events: none;
}

#shell  { width: 1500px; height: 1125px; opacity: .15; }
#lorenz { width: 1050px; height: 1050px; opacity: .15; }
#orb    { width: 430px;  height: 430px;  opacity: .25; }

/* ---------- 4. sky ---------- */

#introSky {
  /* T=0 state. The parser paints before the first rAF frame, so without this the
     opening frame would flash the finished end card. intro.js overwrites it. */
  opacity: 0;
  position: absolute;
  inset: 0;
}

#skyStars circle { fill: #f0eee8; }
#skyLinks line   { stroke: #f0eee8; stroke-width: 0.8; }

/* ---------- 5. Ken-Burns stills ---------- */

#photos {
  /* T=0 state. The parser paints before the first rAF frame, so without this the
     opening frame would flash the finished end card. intro.js overwrites it. */
  opacity: 0;
  position: absolute;
  inset: 0;
}

/* The prototype wrapped each still in a <Shot> whose only job was the
   visibility toggle, around an identical inset-0 box. Flattened here —
   same paint order, same clipping, one node fewer per still. */
.ken {
  position: absolute;
  inset: 0;
  overflow: hidden;
  background: #050505;
  visibility: hidden;
}

.ken-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: grayscale(1) contrast(1.12) brightness(.82);
}

.ken-sweep {
  position: absolute;
  top: -220px;
  bottom: -220px;
  left: 0;
  width: 340px;
  opacity: .1;
  mix-blend-mode: screen;
}

.ken-vig {
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse at 50% 45%, rgba(5,5,5,0) 42%, rgba(5,5,5,.74) 100%);
}

.ken-frame {
  position: absolute;
  inset: 46px;
  border: 1px solid rgba(255,255,255,.26);
}

/* ---------- 6. emblem ---------- */

#emblem {
  /* T=0 state. The parser paints before the first rAF frame, so without this the
     opening frame would flash the finished end card. intro.js overwrites it. */
  opacity: 0;
  position: absolute;
  left: 50%;
  top: 46%;
  transform: translate(-50%, -50%);
}

.em-inner {
  position: relative;
  width: 430px;
  height: 430px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.em-circle {
  position: relative;
  width: 340px;
  height: 340px;
  border-radius: 50%;
  overflow: hidden;
  box-shadow: 0 30px 90px rgba(0,0,0,.8), 0 0 70px rgba(255,255,255,.06);
}

.em-photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: grayscale(1) contrast(1.08);
}

.em-ring {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

#emRingComet { display: none; }

/* ---------- 7. calligraphy wordmark ---------- */

#wordmark {
  /* T=0 state. The parser paints before the first rAF frame, so without this the
     opening frame would flash the finished end card. intro.js overwrites it. */
  opacity: 0;
  position: absolute;
  left: 50%;
  top: 50%;
  width: 460px;
  filter: drop-shadow(0 0 26px rgba(255,255,255,.14));
  z-index: 3;
  transform: translate(-50%, -50%);
}

/* ---------- 8. MBZ latin wordmark ---------- */

#mbz {
  /* T=0 state. The parser paints before the first rAF frame, so without this the
     opening frame would flash the finished end card. intro.js overwrites it. */
  opacity: 0;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%,-50%) translateY(300px);
  z-index: 3;
  font-family: 'Cinzel', serif;
  font-weight: 500;
  font-size: 62px;
  color: #f4f1ea;
  white-space: nowrap;
  text-shadow: 0 0 40px rgba(255,255,255,.16);
}

/* ---------- 9. caption ---------- */

#caption {
  /* T=0 state. The parser paints before the first rAF frame, so without this the
     opening frame would flash the finished end card. intro.js overwrites it. */
  opacity: 0;
  position: absolute;
  left: 0;
  right: 0;
  top: 96px;
  text-align: center;
  z-index: 3;
  font-family: 'Amiri', serif;
  font-weight: 700;
  font-size: 46px;
  color: #f2efe8;
}

/* ---------- 10. end card ---------- */

#enter {
  /* T=0 state. The parser paints before the first rAF frame, so without this the
     opening frame would flash the finished end card. intro.js overwrites it. */
  opacity: 0;
  cursor: pointer;
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 3;
  /* The prototype left this box clickable from T=0 even while it was
     fully transparent — a tap 300px below centre at second 5 would leave
     the film, and would also eat the tap that starts the narration.
     intro.js turns pointer events (and tab focus) on only once the box
     is actually visible. */
  pointer-events: none;
  transform: translate(-50%, -50%);
}

.enter-box {
  position: relative;
  white-space: nowrap;
  color: rgba(244,241,234,.95);
  font-size: 26px;
  padding: 16px 52px;
  border: 1px solid rgba(255,255,255,.45);
  border-radius: 3px;
  background: rgba(255,255,255,.035);
}

.enter-neon {
  position: absolute;
  inset: -3px;
  width: calc(100% + 6px);
  height: calc(100% + 6px);
  overflow: visible;
  pointer-events: none;
}

.enter-neon rect {
  width: calc(100% - 6px);
  height: calc(100% - 6px);
}

#enterComet1 { filter: drop-shadow(0 0 6px rgba(255,255,255,.85)); }

.enter-en    { font-family: 'Cinzel', serif; font-weight: 500; letter-spacing: .26em; }
.enter-slash { font-family: 'Cinzel', serif; opacity: .55; margin: 0 20px; }
.enter-ar    { font-family: 'Amiri', serif; font-weight: 700; font-size: 32px; }

#endCircle {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%,-50%) translateY(-345px);
  width: 280px;
  height: 280px;
  z-index: 3;
  display: none;
}

.end-inner {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  overflow: hidden;
  box-shadow: 0 30px 90px rgba(0,0,0,.8), 0 0 0 1px rgba(255,255,255,.16), 0 0 70px rgba(255,255,255,.06);
}

.end-photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: grayscale(1) contrast(1.08);
}

.end-ring {
  position: absolute;
  inset: -12px;
  width: calc(100% + 24px);
  height: calc(100% + 24px);
}

#endComet { filter: drop-shadow(0 0 5px rgba(255,255,255,.8)); }

#credit {
  /* T=0 state. The parser paints before the first rAF frame, so without this the
     opening frame would flash the finished end card. intro.js overwrites it. */
  opacity: 0;
  cursor: pointer;
  position: absolute;
  left: 46px;
  bottom: 38px;
  z-index: 3;
  transform-origin: left center;
  font-family: 'Noto Sans', sans-serif;
  font-size: 17px;
  letter-spacing: .06em;
  color: #ffffff;
  text-decoration: none;
  /* same reason as #enter: invisible text must not be a live link */
  pointer-events: none;
}

/* ---------- 11. grain + vignette ---------- */

#grain {
  position: absolute;
  inset: 0;
  background-image: url(/assets/grain.png?v=9600e063);
  background-size: 190px 190px;
  opacity: .06;
  mix-blend-mode: overlay;
  z-index: 5;
  pointer-events: none;
}

#vignette {
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse at 50% 45%, rgba(5,5,5,0) 55%, rgba(5,5,5,.5) 100%);
  z-index: 5;
  pointer-events: none;
}

/* ---------- 12. poem ----------
   Centred on the end card where the www.mbz.ae lockup used to sit, under
   the calligraphy and above the JOURNEY box. intro.js writes the entrance
   (opacity / transform / blur) on #poem and the verse cycle on #poemLine;
   the title and its rule ride the container and never leave. */

#poem {
  /* T=0 state. The parser paints before the first rAF frame, so without this the
     opening frame would flash the finished end card. intro.js overwrites it. */
  opacity: 0;
  display: none;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%) translateY(225px);
  width: 760px;
  text-align: center;
  z-index: 6;
  pointer-events: none;
}

#poemTitle {
  font-family: 'Amiri', serif;
  font-weight: 700;
  font-size: 54px;
  /* Amiri's natural line box is ~1.9em tall; unpinned, the grown title
     pushes the block into the calligraphy above and the box below */
  line-height: 1.4;
  color: #f4f1ea;
  text-shadow: 0 0 40px rgba(255,255,255,.14);
  margin-bottom: 12px;
}

#poemRule {
  width: 90px;
  height: 1px;
  background: rgba(255,255,255,.4);
  opacity: .6;
  margin: 0 auto 26px;
}

#poemLine {
  min-height: 84px;
  font-family: 'Amiri', serif;
  font-size: 46px;
  line-height: 1.8;
  color: #f2efe8;
  text-shadow: 0 0 30px rgba(255,255,255,.1);
}

/* ---------- the gate ----------
   The visitor's first click, made into a doorway. Visuals are the v2
   gate's: its radial background, its wordmark size, its button. */

#gate {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: radial-gradient(ellipse at 50% 32%, #0c0c0d 0%, #050505 62%);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 26px;
  cursor: pointer;
  transition: opacity .9s ease;
}

#gate.is-leaving { opacity: 0; pointer-events: none; }

/* Until intro.js has wired the gate (it paints ~150ms in; on a slow link
   the scripts land seconds later), the box is dim and the cursor plain, so
   a not-yet-live gate never looks tappable. */
#gate:not(.is-ready) { cursor: default; }
#gate:not(.is-ready) #gateBox { opacity: .35; }

#gateNoscript {
  font-family: 'Amiri', serif;
  font-size: 20px;
  color: #efece5;
}

#gateWordmark {
  width: clamp(190px, 24vw, 280px);
  display: block;
  filter: drop-shadow(0 0 22px rgba(255,255,255,.12));
}

#gateBox {
  display: flex;
  align-items: baseline;
  gap: 16px;
  border: 1px solid rgba(255,255,255,.38);
  padding: 16px 52px;
  color: #efece5;
  transition: all .35s ease;
}

#gate:hover #gateBox { background: #efece5; color: #0a0a0a; border-color: #efece5; }

#gateBox .enter-en    { font-family: 'Cinzel', serif; font-size: 17px; letter-spacing: .22em; }
#gateBox .enter-slash { opacity: .45; font-family: 'Amiri', serif; font-size: 17px; }
#gateBox .enter-ar    { font-family: 'Amiri', serif; font-weight: 700; font-size: 20px; }

#gateDomain {
  font-family: 'Cinzel', serif;
  font-size: clamp(15px, 2vw, 19px);
  letter-spacing: .3em;
  padding-left: .3em;
  color: #f4f1ea;
  opacity: .8;
}

/* ---------- portrait ----------
   Cover-fit crops the 1920-wide frame to a centred band roughly 500
   composition-pixels wide on a phone. Everything centre-composed already
   fits; the two exceptions are handled here. The credit override uses no
   transform — intro.js writes a scale() on it every frame. */

@media (orientation: portrait) {
  /* the longest poem lines outrun the visible band at their authored 46px */
  #poemTitle { font-size: 42px; }
  #poemLine  { font-size: 30px; }

  /* the box is ~500 units wide with its pulse; the band on a 20:9 phone is
     ~486, and its side borders and running light fell off both edges */
  .enter-box { padding: 16px 20px; }

  /* authored against the left edge, which the crop removes */
  #credit {
    left: 0;
    right: 0;
    bottom: 38px;
    text-align: center;
    transform-origin: center;
  }
}

/* ---------- landscape phones ----------
   The whole 1920x1080 frame contain-fits a short screen at 0.28–0.36
   scale, which left the only exit a 150x28px box with an 8px label and a
   5px credit. Mirrors the portrait override above; tablets and desktops
   (taller than 500px) are untouched. */

@media (orientation: landscape) and (max-height: 500px) {
  .enter-box { font-size: 34px; padding: 18px 60px; }
  .enter-ar  { font-size: 42px; }
  #enter     { top: calc(50% + 30px); }
  #credit    { font-size: 28px; }
}
