/* =========================================================================
   SKIN VISION — cinematic two-scene prototype
   ========================================================================= */

:root{
  --ink:            #f4f1ec;
  --ink-dim:        rgba(244,241,236,.56);
  --ink-faint:      rgba(244,241,236,.24);
  --line:           rgba(244,241,236,.16);
  --bg:             #07070a;
  --sand:           #d8c3a5;
  --sand-deep:      #b99f7e;
  --gold:           #b4974f;   /* sampled from brand/logo.svg */

  --ease-cine:      cubic-bezier(.16,1,.3,1);
  --ease-veil:      cubic-bezier(.65,0,.2,1);

  --pad-x:          clamp(20px, 4.2vw, 76px);
  --pad-y:          clamp(18px, 3.4vh, 44px);

  --t-transition:   1400ms;   /* mirrored from scenes.config.js */
  --t-swap:         380ms;

  --font-ar:        "IBM Plex Sans Arabic", "Noto Sans Arabic", system-ui, sans-serif;
  --font-lat:       "IBM Plex Sans", ui-sans-serif, system-ui, sans-serif;
}

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

html,body{
  margin:0; padding:0;
  height:100%; width:100%;
  overflow:hidden;                 /* no traditional page scrolling */
  overscroll-behavior:none;
  background:var(--bg);
  color:var(--ink);
  font-family:var(--font-lat);
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
}

body{ touch-action:none; }

button{ font:inherit; color:inherit; background:none; border:0; cursor:pointer; }
svg{ width:100%; height:100%; fill:none; stroke:currentColor; stroke-width:1.4;
     stroke-linecap:round; stroke-linejoin:round; }

::selection{ background:var(--sand); color:#0a0a0c; }

/* ── Stage ───────────────────────────────────────────────────────────────── */

.stage{
  position:fixed; inset:0;
  overflow:hidden;
  background:#000;
  isolation:isolate;
  /* The stage must never scroll — focus or an oversized child would otherwise
     drag the whole fixed chrome out of frame. */
  overscroll-behavior:none;
}

.scene-track{ position:absolute; inset:0; overflow:hidden; }

/* ── Scene layer ─────────────────────────────────────────────────────────── */

.scene{
  position:absolute; inset:0;
  overflow:hidden;              /* the drift push must stay inside the frame */
  opacity:0;
  visibility:hidden;
  transform:scale(1.06);
  filter:blur(14px) saturate(.7);
  transition:
    opacity   var(--t-transition) var(--ease-veil),
    transform var(--t-transition) var(--ease-cine),
    filter    var(--t-transition) var(--ease-veil),
    visibility 0s linear var(--t-transition);
}

/* Reserve compositor memory only for the scenes actually on screen. With five
   scenes loaded, promoting all of them costs layers for nothing. */
.scene.is-active,
.scene.is-leaving,
.scene.is-leaving-back{ will-change:opacity, transform, filter; }

.scene.is-active{
  opacity:1;
  visibility:visible;
  transform:scale(1);
  filter:blur(0) saturate(1);
  transition-delay:0s;
  z-index:2;
}

/* leaving backwards reads as a pull-back rather than a push-in */
.scene.is-leaving{ z-index:1; transform:scale(1.1); }
.scene.is-leaving-back{ z-index:1; transform:scale(.94); }

/* The frame owns the hold push; the video owns its own drift. Separating them
   means the two transforms compose instead of overwriting each other. */
.scene__frame{
  position:absolute; inset:0;
  transform-origin:50% 54%;
  will-change:transform, filter;
}

.scene__video{
  position:absolute; inset:0;
  width:100%; height:100%;
  object-fit:cover;
  object-position:center center;
  display:block;
  background:#000;
  /* a slow breathing push keeps the frame alive between beats */
  animation:sceneDrift 26s var(--ease-cine) infinite alternate;
}

@keyframes sceneDrift{
  from{ transform:scale(1.015); }
  to  { transform:scale(1.075); }
}

/* Four of the five scenes are always off screen — their drift is invisible work
   for the compositor, so it is stopped until the scene comes forward. */
.scene:not(.is-active):not(.is-leaving):not(.is-leaving-back) .scene__video{
  animation-play-state:paused;
}
.scene:not(.is-active) .scene__frame{ will-change:auto; }

/* ── Hold motion ──────────────────────────────────────────────────────────
   The footage has ended but the voice has not. The engine replays the final
   fraction of a second in slow motion; this rides on top of it — a long,
   decelerating push that deliberately never completes, so the shot reads as a
   camera still settling rather than a still image being zoomed. */
.scene.is-holding .scene__frame{
  animation:holdPush 16s cubic-bezier(.18,.72,.31,1) forwards;
}

@keyframes holdPush{
  from{
    transform:scale(1) translate3d(0,0,0);
    filter:saturate(1) brightness(1) contrast(1);
  }
  to{
    transform:scale(1.09) translate3d(0,-1.4%,0);
    filter:saturate(1.07) brightness(1.035) contrast(1.02);
  }
}

/* The vignette closes a touch as the push settles — the frame breathes in. */
.scene.is-holding ~ .vignette,
.stage:has(.scene.is-holding) .vignette{
  animation:holdVignette 16s cubic-bezier(.18,.72,.31,1) forwards;
}
@keyframes holdVignette{
  from{ opacity:1; transform:scale(1); }
  to  { opacity:1; transform:scale(1.04); }
}

/* ── Transcript ──────────────────────────────────────────────────────────── */

.scene__transcript{
  position:absolute;
  z-index:3;
  display:flex;
  pointer-events:none;
  padding:0 var(--pad-x);
  inset:0;
}

.scene__transcript.pos-middle-right{ align-items:center; justify-content:flex-start; }
.scene__transcript.pos-middle-left { align-items:center; justify-content:flex-end;  }
.scene__transcript.pos-bottom-right{ align-items:flex-end; justify-content:flex-start; padding-bottom:19vh; }
.scene__transcript.pos-bottom-left { align-items:flex-end; justify-content:flex-end;  padding-bottom:19vh; }
.scene__transcript.pos-center      { align-items:center;   justify-content:center; }

.phrase{
  max-width:min(21ch, 38vw);
  margin:0;
  font-family:var(--font-ar);
  font-weight:500;
  /* Editorial scale — the phrase is the subject of the frame, not a caption. */
  font-size:clamp(28px, 3.4vw, 66px);
  line-height:1.58;
  letter-spacing:0;          /* Arabic must never be tracked out */
  word-spacing:.04em;
  text-align:right;
  direction:rtl;
  text-wrap:balance;         /* keeps two-line phrases optically even */
  color:var(--ink);
  text-shadow:0 2px 44px rgba(0,0,0,.5), 0 1px 3px rgba(0,0,0,.38);

  /* The block fades as a unit; characters are lit individually while typing. */
  opacity:0;
  transform:translateY(10px);
  transition:
    opacity   560ms var(--ease-cine),
    transform 680ms var(--ease-cine);
  will-change:opacity, transform;
}

.phrase.is-in{ opacity:1; transform:translateY(0); }

/* exit is faster than entry — the eye should never wait on an empty frame */
.phrase.is-out{
  opacity:0;
  transform:translateY(-8px);
  transition-duration:var(--t-swap), var(--t-swap);
}

/* ── Word reveal ──────────────────────────────────────────────────────────
   The phrase is split at spaces only. Arabic never joins across a space, so
   each word renders exactly as it would in plain text — no broken ligatures,
   no doubled glyphs. The word being written is clipped to the exact edge of
   its last written character, which keeps the reveal per-character. */

.phrase{ position:relative; }

.w{
  display:inline-block;
  /* clip-path is the mask; nothing here may alter layout or shaping */
  will-change:clip-path;
}

.caret{
  position:absolute;
  top:0; left:0;
  width:.055em;
  height:1.05em;
  margin-top:.16em;          /* sit on the line, not the box top */
  background:var(--sand);
  border-radius:1px;
  box-shadow:0 0 14px rgba(216,195,165,.5);
  opacity:.92;
  pointer-events:none;
  transition:transform 90ms linear, opacity 420ms var(--ease-cine);
  will-change:transform;
}

/* Solid while writing, breathing once the phrase lands. */
.caret.is-resting{ animation:caretPulse 1.5s var(--ease-cine) infinite; }
@keyframes caretPulse{
  0%,100%{ opacity:.92; } 50%{ opacity:.18; }
}

/* Scene finished — the sentence stays, the caret bows out. */
.phrase.is-settled .caret{ opacity:0; animation:none; }

.scene__transcript.pos-center .phrase{ text-align:center; max-width:min(24ch,72vw); }

/* a localized wash behind the text so it never fights the footage */
.scene__glow{
  position:absolute; inset:0; z-index:2; pointer-events:none;
  opacity:0;
  transition:opacity 900ms var(--ease-cine);
}
.scene.has-phrase .scene__glow{ opacity:1; }

.scene__glow.pos-middle-right{
  background:linear-gradient(270deg, rgba(0,0,0,.62) 0%, rgba(0,0,0,.34) 34%, transparent 62%);
}
.scene__glow.pos-middle-left{
  background:linear-gradient(90deg, rgba(0,0,0,.62) 0%, rgba(0,0,0,.34) 34%, transparent 62%);
}
.scene__glow.pos-bottom-right,
.scene__glow.pos-bottom-left,
.scene__glow.pos-center{
  background:linear-gradient(0deg, rgba(0,0,0,.66) 0%, rgba(0,0,0,.3) 30%, transparent 58%);
}

/* ── Media error state ───────────────────────────────────────────────────── */

.scene__fallback{
  position:absolute; inset:0; z-index:4;
  display:none;
  align-items:center; justify-content:center;
  flex-direction:column; gap:14px;
  background:
    radial-gradient(120% 90% at 50% 40%, #14141a 0%, #08080b 70%);
  font-family:var(--font-ar);
  text-align:center;
  padding:var(--pad-x);
}
.scene.is-unavailable .scene__fallback{ display:flex; }
.scene.is-unavailable .scene__video{ visibility:hidden; }

.scene__fallback-title{
  font-size:clamp(17px,1.5vw,22px); font-weight:500; color:var(--ink-dim); margin:0;
}
.scene__fallback-path{
  font-family:var(--font-lat); direction:ltr;
  font-size:12px; letter-spacing:.06em; color:var(--ink-faint);
  border:1px solid var(--line); border-radius:999px; padding:7px 15px;
}

.scene__loader{
  position:absolute; z-index:4; inset:0;
  display:flex; align-items:center; justify-content:center;
  background:#08080b;
  opacity:1; transition:opacity 700ms var(--ease-cine);
}
.scene.is-ready .scene__loader{ opacity:0; pointer-events:none; }
.scene.is-unavailable .scene__loader{ opacity:0; }

.scene__loader::after{
  content:""; width:34px; height:34px; border-radius:50%;
  border:1px solid var(--line); border-top-color:var(--sand);
  animation:spin 900ms linear infinite;
}
@keyframes spin{ to{ transform:rotate(360deg); } }

/* ── Grade / texture ─────────────────────────────────────────────────────── */

.grade,.grain,.vignette{ position:absolute; inset:0; z-index:5; pointer-events:none; }

.grade{
  background:
    linear-gradient(180deg, rgba(6,6,10,.5) 0%, transparent 24%, transparent 68%, rgba(6,6,10,.62) 100%);
  mix-blend-mode:multiply;
}

.vignette{
  background:radial-gradient(118% 96% at 50% 46%, transparent 46%, rgba(0,0,0,.58) 100%);
}

.grain{
  opacity:.055;
  mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml;utf8,\
<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'>\
<filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/></filter>\
<rect width='160' height='160' filter='url(%23n)' opacity='.9'/></svg>");
  background-size:180px 180px;
  /* background-position, not transform — a transform here would grow the
     stage's scrollable area and shift the fixed chrome. */
  animation:grainShift 6s steps(6) infinite;
}
@keyframes grainShift{
  0%{ background-position:0 0; }        20%{ background-position:-24px 16px; }
  40%{ background-position:18px -26px; } 60%{ background-position:-18px -18px; }
  80%{ background-position:26px 8px; }  100%{ background-position:0 0; }
}

.letterbox{
  position:absolute; left:0; right:0; z-index:6; pointer-events:none;
  height:clamp(14px, 3.4vh, 42px);
  background:#000;
  transform:scaleY(0); transform-origin:top;
  transition:transform 1100ms var(--ease-cine);
}
.letterbox--top{ top:0; }
.letterbox--bottom{ bottom:0; transform-origin:bottom; }
body.is-playing .letterbox{ transform:scaleY(1); }
body.is-transitioning .letterbox{ transform:scaleY(1.55); }

/* ── The cinematic transition veil ───────────────────────────────────────── */

.veil{
  position:absolute; inset:0; z-index:20; pointer-events:none;
  overflow:hidden;            /* the sweep is oversized — never let it grow the stage */
  background:#040406;
  opacity:0;
  transition:opacity 620ms var(--ease-veil);
}
body.is-transitioning .veil{ opacity:.82; transition-duration:520ms; }

.veil__sweep{
  position:absolute; inset:-30% -60%;
  background:linear-gradient(105deg,
    transparent 38%,
    rgba(216,195,165,.16) 47%,
    rgba(244,241,236,.30) 50%,
    rgba(216,195,165,.16) 53%,
    transparent 62%);
  transform:translateX(-120%);
  opacity:0;
}
body.is-transitioning .veil__sweep{
  animation:sweep var(--t-transition) var(--ease-veil) forwards;
}
@keyframes sweep{
  0%  { transform:translateX(-120%); opacity:0; }
  22% { opacity:1; }
  78% { opacity:1; }
  100%{ transform:translateX(120%);  opacity:0; }
}

/* ── Navigation ──────────────────────────────────────────────────────────── */

.nav{
  position:absolute; z-index:12;
  top:0; left:0; right:0;
  display:flex; align-items:center; justify-content:space-between;
  padding:calc(var(--pad-y) + clamp(14px,3.4vh,42px)) var(--pad-x) var(--pad-y);
  direction:ltr;
  opacity:0; transform:translateY(-10px);
  transition:opacity 900ms var(--ease-cine) 200ms, transform 900ms var(--ease-cine) 200ms;
}
body.is-playing .nav{ opacity:1; transform:none; }

/* ── Brand ────────────────────────────────────────────────────────────────
   The V monogram with its leaf, and the Arabic wordmark stacked beside it.
   One component, two sizes: --sm in the nav, --lg on the splash. */

.brand{
  display:flex; align-items:center; gap:12px;
  text-decoration:none;
  direction:rtl;
  transition:opacity 400ms var(--ease-cine);
}
.brand--sm:hover{ opacity:.72; }

.brand__mark{ flex:none; display:block; }
.brand__mark svg{ width:100%; height:100%; stroke:none; }

.bm-thick, .bm-thin, .bm-dot{ fill:var(--gold); }
.bm-leaf{ fill:none; stroke:var(--gold); stroke-width:2.4; }

.brand__word{
  display:flex; flex-direction:column; align-items:flex-start;
  font-family:var(--font-ar);
  color:var(--gold);
  line-height:1.06;
}
.brand__word em,
.brand__word i{ font-style:normal; display:block; }
.brand__word em{ font-weight:500; }
.brand__word i{ font-weight:400; opacity:.82; }

/* nav */
.brand--sm .brand__mark{ width:29px; height:33px; }
.brand--sm .brand__word{ font-size:15px; }

/* splash */
.brand--lg{ gap:18px; }
.brand--lg .brand__mark{ width:clamp(38px,3.4vw,52px); height:clamp(43px,3.8vw,58px); }
.brand--lg .brand__word{ font-size:clamp(17px,1.6vw,23px); }

/* Real artwork dropped into ./brand/ takes over from the drawn mark. */
.brand__file{ display:none; }
.brand.has-artwork .brand__mark,
.brand.has-artwork .brand__word{ display:none; }
.brand.has-artwork .brand__file{ display:block; width:auto; }
.brand--sm.has-artwork .brand__file{ height:38px; }
.brand--lg.has-artwork .brand__file{ height:clamp(46px,4.4vw,68px); }



/* ── Scene tag ────────────────────────────────────────────────────────────
   Number, rule, name — side by side. The same component labels the scene in
   the navigation and on every timeline marker, reading from the same string,
   so the two can never disagree. */

.scene-tag{
  display:flex; align-items:center;
  gap:clamp(9px,.9vw,14px);
  direction:ltr;               /* the number leads; the name sets its own dir */
  white-space:nowrap;
}

.scene-tag__num{
  font-family:var(--font-lat);
  font-weight:500;
  letter-spacing:.18em;
  font-variant-numeric:tabular-nums;
  line-height:1;
  color:var(--ink-faint);
  transition:color 600ms var(--ease-cine), transform 600ms var(--ease-cine),
             text-shadow 600ms var(--ease-cine);
}

.scene-tag__name{
  font-family:var(--font-ar);
  font-weight:400;
  letter-spacing:0;            /* Arabic is never tracked out */
  line-height:1.25;
  color:var(--ink-faint);
  transition:color 600ms var(--ease-cine);
}

/* navigation */
.scene-tag--nav .scene-tag__num{ font-size:clamp(11px,.95vw,13px); color:var(--gold); }
.scene-tag--nav .scene-tag__name{ font-size:clamp(12px,1vw,15px); color:var(--gold); }

/* timeline marker */
.scene-tag--mark .scene-tag__num{ font-size:clamp(12px,1.05vw,16px); }
.scene-tag--mark .scene-tag__name{ font-size:clamp(11px,.92vw,14px); }

/* ── Controls ────────────────────────────────────────────────────────────── */

.controls{
  position:absolute; z-index:12;
  right:var(--pad-x);
  bottom:calc(var(--pad-y) + clamp(56px,9vh,96px));
  display:flex; flex-direction:column; gap:10px;
  direction:ltr;
  opacity:0; transform:translateX(14px);
  transition:opacity 900ms var(--ease-cine) 320ms, transform 900ms var(--ease-cine) 320ms;
}
body.is-playing .controls{ opacity:1; transform:none; }

.ctrl{
  width:42px; height:42px; padding:11px;
  border:1px solid var(--line); border-radius:50%;
  color:var(--ink-dim);
  backdrop-filter:blur(10px);
  background:rgba(10,10,14,.24);
  transition:color 380ms var(--ease-cine), border-color 380ms var(--ease-cine),
             background 380ms var(--ease-cine), transform 380ms var(--ease-cine),
             opacity 380ms var(--ease-cine);
}
.ctrl:hover:not(:disabled){
  color:var(--ink); border-color:rgba(244,241,236,.4);
  background:rgba(20,20,26,.5); transform:translateY(-2px);
}
.ctrl:disabled{ opacity:.22; cursor:default; }
.ctrl:focus-visible{ outline:1px solid var(--sand); outline-offset:3px; }

.ctrl .ico-mute{ display:none; }
.ctrl.is-muted{ color:var(--ink); border-color:rgba(244,241,236,.34); }
.ctrl.is-muted .ico-sound{ display:none; }
.ctrl.is-muted .ico-mute{ display:block; }

/* ── Audio-unavailable flag ──────────────────────────────────────────────── */

.audio-flag{
  position:absolute; z-index:12;
  left:var(--pad-x);
  bottom:calc(var(--pad-y) + clamp(56px,9vh,96px));
  display:flex; align-items:center; gap:9px;
  padding:8px 14px;
  border:1px solid var(--line); border-radius:999px;
  background:rgba(10,10,14,.34); backdrop-filter:blur(10px);
  font-family:var(--font-ar); font-size:12px; color:var(--ink-dim);
  direction:rtl;
}
.audio-flag[hidden]{ display:none; }
.audio-flag svg{ width:15px; height:15px; flex:none; }

/* ── Timeline ─────────────────────────────────────────────────────────────
   A single unbroken rail. Every scene owns an equal span of it and the spans
   butt directly together — no connector, no margin, no gap. The markers ride
   on top of the line instead of interrupting it. */

.timeline{
  position:absolute; z-index:12;
  left:var(--pad-x); right:var(--pad-x);
  bottom:calc(var(--pad-y) + clamp(14px,3.4vh,42px));
  direction:ltr;
  opacity:0; transform:translateY(12px);
  transition:opacity 900ms var(--ease-cine) 420ms, transform 900ms var(--ease-cine) 420ms;
}
body.is-playing .timeline{ opacity:1; transform:none; }

.tl-track{
  position:relative;
  display:flex;
  height:1px;
  background:var(--line);
}

.tl-seg{
  position:relative;
  flex:1 1 0;
  height:100%;
  overflow:hidden;      /* the fill is clipped to its own span */
}

.tl-seg__fill{
  position:absolute; inset:0;
  transform-origin:left center;
  transform:scaleX(0);
  background:linear-gradient(90deg, var(--gold), var(--sand));
  transition:transform 140ms linear;
}
.tl-seg__fill.no-ease{ transition:none; }

/* ── Markers ───────────────────────────────────────────────────────────── */

.tl-marks{ position:relative; height:0; }

.tl-node{
  position:absolute;
  top:0;
  transform:translate(-50%, -50%);
  display:flex; flex-direction:column; align-items:center;
  padding:0;
  transition:opacity 500ms var(--ease-cine);
}

.tl-node__dot{
  position:relative;
  width:7px; height:7px; border-radius:50%;
  background:var(--ink-faint);
  transition:background 600ms var(--ease-cine), transform 600ms var(--ease-cine),
             box-shadow 600ms var(--ease-cine);
}
.tl-node.is-done .tl-node__dot{ background:var(--sand-deep); }
.tl-node.is-active .tl-node__dot{
  background:var(--gold);
  transform:scale(1.5);
  box-shadow:0 0 0 4px rgba(180,151,79,.16), 0 0 14px rgba(180,151,79,.5);
}
.tl-node.is-active .tl-node__dot::after{
  content:""; position:absolute; inset:-7px;
  border-radius:50%; border:1px solid rgba(180,151,79,.4);
  animation:pulseRing 2.6s var(--ease-cine) infinite;
}
@keyframes pulseRing{
  0%  { transform:scale(.7); opacity:.9; }
  100%{ transform:scale(1.8); opacity:0; }
}

/* The label sits above the dot and reads rightward, describing the span of
   rail it opens. */
.tl-node .scene-tag{
  position:absolute;
  bottom:calc(100% + 11px);
  left:0;
  pointer-events:none;
}

.tl-node.is-done .scene-tag__name,
.tl-node.is-done .scene-tag__num{ color:var(--ink-dim); }

/* The scene you are in is unmistakable. */
.tl-node.is-active .scene-tag__name{ color:var(--gold); text-shadow:0 0 18px rgba(180,151,79,.35); }
.tl-node.is-active .scene-tag__num{
  color:var(--gold);
  transform:scale(1.12);
  text-shadow:0 0 18px rgba(180,151,79,.45);
}

.tl-node:hover .scene-tag__name,
.tl-node:hover .scene-tag__num{ color:var(--ink); }
.tl-node:focus-visible{ outline:1px solid var(--sand); outline-offset:6px; border-radius:2px; }

/* ── Scroll hint ─────────────────────────────────────────────────────────── */

.hint{
  position:absolute; z-index:11;
  left:50%; transform:translateX(-50%);
  bottom:calc(var(--pad-y) + clamp(56px,9vh,96px));
  display:flex; flex-direction:column; align-items:center; gap:10px;
  font-family:var(--font-ar); font-size:12px; letter-spacing:.04em;
  color:var(--ink-faint);
  opacity:0;
  transition:opacity 800ms var(--ease-cine);
}
body.is-playing .hint.is-shown{ opacity:1; }

.hint__line{
  width:1px; height:34px;
  background:linear-gradient(180deg, var(--ink-faint), transparent);
  animation:hintFall 2.4s var(--ease-cine) infinite;
}
@keyframes hintFall{
  0%  { transform:scaleY(0); transform-origin:top; opacity:0; }
  35% { transform:scaleY(1); transform-origin:top; opacity:1; }
  70% { transform:scaleY(1); transform-origin:bottom; opacity:1; }
  100%{ transform:scaleY(0); transform-origin:bottom; opacity:0; }
}

/* ── Loader ───────────────────────────────────────────────────────────────
   No bar. The mark itself fills with gold as the film loads — a dim plate
   underneath, a lit copy clipped to the progress line, and a glowing meniscus
   riding the boundary between them. The count sits beneath in thin figures. */

.loader{
  position:absolute; inset:0; z-index:40;
  display:flex; align-items:center; justify-content:center;
  overflow:hidden;
  background:
    radial-gradient(120% 92% at 50% 46%, #15120c 0%, #0a0908 48%, #050506 100%);
  transition:opacity 900ms var(--ease-veil), filter 900ms var(--ease-veil);
  --p:0;                       /* progress, 0 → 1, set from app.js */
}
.loader.is-done{ opacity:0; filter:blur(10px); pointer-events:none; }

/* Ambient warmth that swells as the load completes. */
.loader__aura{
  position:absolute; border-radius:50%;
  filter:blur(90px); mix-blend-mode:screen;
  pointer-events:none;
  opacity:calc(.25 + var(--p) * .75);
  transition:opacity 600ms var(--ease-cine);
}
.loader__aura--a{
  width:54vmax; height:54vmax; left:-12vmax; top:-16vmax;
  background:radial-gradient(circle, rgba(198,168,104,.26) 0%, rgba(198,168,104,0) 68%);
  animation:glowA 26s var(--ease-cine) infinite alternate;
}
.loader__aura--b{
  width:46vmax; height:46vmax; right:-14vmax; bottom:-18vmax;
  background:radial-gradient(circle, rgba(216,195,165,.2) 0%, rgba(216,195,165,0) 70%);
  animation:glowB 34s var(--ease-cine) infinite alternate;
}

.loader__inner{
  position:relative; z-index:2;
  display:flex; flex-direction:column; align-items:center;
  padding:0 var(--pad-x);
}

/* ── The filling mark ──────────────────────────────────────────────────── */

.loader__mark{
  position:relative;
  opacity:0;
  animation:riseIn 1200ms var(--ease-cine) 120ms forwards;
}
/* The loader is the one place the mark is the whole composition. */
.loader__mark .brand--lg{ gap:22px; }
.loader__mark .brand--lg .brand__mark{ width:clamp(58px,5.6vw,86px); height:clamp(66px,6.3vw,96px); }
.loader__mark .brand--lg .brand__word{ font-size:clamp(24px,2.4vw,36px); }
.loader__mark .brand.has-artwork .brand__file{ height:clamp(64px,6.4vw,96px); }

/* Unlit: all but gone. A 8% ghost, just enough to read the silhouette so the
   viewer knows what is filling — the gold itself carries the progress. */
.loader__plate{
  opacity:.08;
  filter:brightness(.9);
  transition:opacity 700ms var(--ease-cine);
}

/* When the drawn mark is in use (no artwork file supplied) it can be rendered
   as a true outline, which is closer to the intent than a faded solid. The
   supplied logo.svg embeds its V as a raster, so it can only be ghosted. */
.loader__plate .brand:not(.has-artwork){ opacity:1; }
.loader__plate .brand:not(.has-artwork) .bm-thick,
.loader__plate .brand:not(.has-artwork) .bm-thin,
.loader__plate .brand:not(.has-artwork) .bm-dot{
  fill:none; stroke:var(--gold); stroke-width:1.4;
}
.loader__plate .brand:not(.has-artwork) .bm-leaf{ stroke-width:1.4; }
.loader__plate .brand:not(.has-artwork) .brand__word{
  color:transparent;
  -webkit-text-stroke:.55px var(--gold);
}
/* strokes are thin, so the outline needs a little more presence than a ghost */
.loader__plate:has(.brand:not(.has-artwork)){ opacity:.34; }

/* Lit: the same mark in full gold, revealed from the bottom up. */
.loader__lit{
  position:absolute; inset:0;
  clip-path:inset(calc((1 - var(--p)) * 100%) 0 0 0);
  transition:clip-path 420ms var(--ease-cine);
  filter:drop-shadow(0 0 18px rgba(198,168,104,.4));
}

/* The surface of the rising gold. */
.loader__meniscus{
  position:absolute; left:-2%; right:-2%;
  height:1px;
  bottom:calc(var(--p) * 100%);
  background:linear-gradient(90deg,
    transparent 0%, rgba(240,214,152,.55) 26%, #fff6de 50%,
    rgba(240,214,152,.55) 74%, transparent 100%);
  box-shadow:0 0 14px rgba(240,214,152,.55);
  opacity:calc(1 - var(--p) * var(--p));   /* fades out as it reaches the top */
  transition:bottom 420ms var(--ease-cine), opacity 420ms linear;
}

/* Once full, the mark settles and breathes rather than sitting inert. */
.loader.is-full .loader__lit{ animation:markSettle 1.1s var(--ease-cine); }
@keyframes markSettle{
  0%  { filter:drop-shadow(0 0 18px rgba(198,168,104,.4)); transform:scale(1); }
  38% { filter:drop-shadow(0 0 44px rgba(240,214,152,.95)); transform:scale(1.035); }
  100%{ filter:drop-shadow(0 0 22px rgba(198,168,104,.5)); transform:scale(1); }
}

/* ── The count ─────────────────────────────────────────────────────────── */

.loader__count{
  display:flex; align-items:flex-start; gap:4px;
  direction:ltr;               /* the page is RTL; "87%" must not become "%87" */
  margin-top:clamp(30px,4.6vh,52px);
  font-family:var(--font-lat);
  color:var(--sand);
  opacity:0;
  animation:riseIn 1100ms var(--ease-cine) 380ms forwards;
}
.loader__pct{
  font-size:clamp(52px,6.4vw,92px);
  font-weight:200;
  line-height:.9;
  letter-spacing:-.02em;
  font-variant-numeric:tabular-nums;
  background:linear-gradient(180deg, #f6ecd4 0%, var(--gold) 100%);
  -webkit-background-clip:text; background-clip:text;
  color:transparent;
}
.loader__sign{
  margin-top:.5em;
  font-size:clamp(13px,1.2vw,17px);
  font-weight:300;
  color:var(--gold);
  opacity:.55;
}

/* ── Intro gate ───────────────────────────────────────────────────────────
   Dark and cinematic again, but built from the brand rather than from noise:
   the wordmark blown up and thrown far out of focus as texture, two slow warm
   glows, and a thin drift of dust. The film begins as the plate lifts away. */

.gate{
  position:absolute; inset:0; z-index:30;
  display:flex; align-items:center; justify-content:center;
  overflow:hidden;
  background:
    radial-gradient(120% 92% at 50% 42%, #14110d 0%, #0a0908 46%, #050506 100%);
  transition:opacity 1300ms var(--ease-veil), filter 1300ms var(--ease-veil);
}
.gate.is-dismissed{ opacity:0; filter:blur(12px); pointer-events:none; }
/* Nothing behind a dismissed gate needs to keep animating. */
.gate.is-dismissed .mote,
.gate.is-dismissed .gate__glow{ animation-play-state:paused; }

.gate__bg{ position:absolute; inset:0; z-index:0; pointer-events:none; }

/* Flowing gold behind the type. Blurred enough that the copy stays the subject
   and the compression noise disappears, but not so much that the movement is
   lost — the whole point is that the plate is alive. */
.gate__motion{
  position:absolute; inset:0;
  width:100%; height:100%;
  object-fit:cover;
  display:block;
  opacity:0;
  filter:blur(9px) saturate(1.25) brightness(1.06) contrast(1.08);
  transform:scale(1.09);          /* hides the soft edge the blur leaves */
  transition:opacity 1400ms var(--ease-cine);
}
.gate__motion.is-ready{ opacity:.92; }

/* Warm light, moving slowly enough that you feel it rather than watch it. */
.gate__glow{
  position:absolute; border-radius:50%;
  filter:blur(80px); mix-blend-mode:screen;
  will-change:transform;
}
.gate__glow--a{
  width:56vmax; height:56vmax; left:-14vmax; top:-18vmax;
  background:radial-gradient(circle, rgba(198,168,104,.17) 0%, rgba(198,168,104,0) 68%);
  animation:glowA 30s var(--ease-cine) infinite alternate;
}
.gate__glow--b{
  width:48vmax; height:48vmax; right:-16vmax; bottom:-20vmax;
  background:radial-gradient(circle, rgba(216,195,165,.13) 0%, rgba(216,195,165,0) 70%);
  animation:glowB 38s var(--ease-cine) infinite alternate;
}
@keyframes glowA{
  from{ transform:translate3d(0,0,0) scale(1); opacity:.8; }
  to  { transform:translate3d(12vmax,8vmax,0) scale(1.2); opacity:1; }
}
@keyframes glowB{
  from{ transform:translate3d(0,0,0) scale(1.14); opacity:1; }
  to  { transform:translate3d(-10vmax,-7vmax,0) scale(1); opacity:.65; }
}

/* Dust — positions assigned in app.js so the field never repeats. */
.gate__dust{ position:absolute; inset:0; }
.mote{
  position:absolute; border-radius:50%;
  background:rgba(244,241,236,.6);
  box-shadow:0 0 6px rgba(216,195,165,.45);
  animation-name:moteRise;
  animation-timing-function:cubic-bezier(.42,0,.35,1);
  animation-iteration-count:infinite;
  will-change:transform, opacity;
}
@keyframes moteRise{
  0%  { transform:translate3d(0,0,0); opacity:0; }
  14% { opacity:1; }
  80% { opacity:1; }
  100%{ transform:translate3d(var(--dx), -108vh, 0); opacity:0; }
}

.gate__vignette{
  position:absolute; inset:0;
  background:
    radial-gradient(58% 46% at 50% 46%, rgba(5,5,6,.62) 0%, rgba(5,5,6,.26) 56%, transparent 82%),
    radial-gradient(128% 104% at 50% 50%, transparent 52%, rgba(3,3,4,.72) 100%);
}

.gate__inner{
  position:relative; z-index:2;
  display:flex; flex-direction:column; align-items:center; text-align:center;
  padding:0 var(--pad-x);
}

.brand--lg{
  opacity:0; animation:riseIn 1100ms var(--ease-cine) 160ms forwards;
}

.gate__title{
  margin:clamp(28px,4vh,44px) 0 0;
  font-family:var(--font-ar); font-weight:400;
  font-size:clamp(34px, 4.9vw, 80px);
  line-height:1.38; letter-spacing:0;
  color:var(--ink);
  text-shadow:0 2px 50px rgba(0,0,0,.5);
  opacity:0; animation:riseIn 1200ms var(--ease-cine) 320ms forwards;
}

.gate__sub{
  margin:20px 0 0;
  font-family:var(--font-ar); font-weight:300;
  font-size:clamp(15px,1.35vw,20px); line-height:1.9;
  color:var(--sand); opacity:0;
  max-width:36ch;
  animation:riseIn 1200ms var(--ease-cine) 460ms forwards;
}

@keyframes riseIn{
  from{ opacity:0; transform:translateY(18px); filter:blur(8px); }
  to  { opacity:1; transform:none;             filter:blur(0); }
}
.gate__sub{ animation-fill-mode:forwards; }

/* The CTA: an outlined pill that fills with gold from the leading edge. */
.gate__cta{
  position:relative;
  margin-top:clamp(36px,5vh,58px);
  padding:18px 54px;
  border:1px solid rgba(198,168,104,.5);
  border-radius:999px;
  overflow:hidden;
  font-family:var(--font-ar); font-weight:500;
  font-size:clamp(14px,1.15vw,17px);
  color:var(--ink);
  backdrop-filter:blur(6px);
  opacity:0; animation:riseIn 1100ms var(--ease-cine) 620ms forwards;
  transition:color 600ms var(--ease-cine), border-color 600ms var(--ease-cine),
             transform 600ms var(--ease-cine), box-shadow 600ms var(--ease-cine);
  box-shadow:0 0 0 0 rgba(198,168,104,0);
}
.gate__cta-label{ position:relative; z-index:2; }

.gate__cta-fill{
  position:absolute; inset:0; z-index:1;
  background:linear-gradient(90deg, var(--gold) 0%, var(--sand) 100%);
  transform:scaleX(0); transform-origin:right center;   /* RTL: fills from the right */
  transition:transform 700ms var(--ease-cine);
}

.gate__cta:hover{
  color:#141109;
  border-color:var(--sand);
  transform:translateY(-3px);
  box-shadow:0 18px 44px -20px rgba(198,168,104,.7);
}
.gate__cta:hover .gate__cta-fill{ transform:scaleX(1); }
.gate__cta:active{ transform:translateY(-1px) scale(.99); }
.gate__cta:focus-visible{ outline:1px solid var(--sand); outline-offset:5px; }

.gate__note{
  margin:24px 0 0;
  font-family:var(--font-ar); font-size:12px; color:var(--ink-faint);
  opacity:0; animation:riseIn 1100ms var(--ease-cine) 760ms forwards;
}
.gate__note.is-warning{ color:#c98d78; }


/* ── Closing marketing screen ─────────────────────────────────────────────
   Temporary by design: this whole section comes out once the film runs its
   full six scenes and the closing beat lives in the footage instead. */

.outro{
  position:absolute; inset:0; z-index:25;
  display:flex; align-items:center; justify-content:center;
  background:
    radial-gradient(120% 92% at 50% 44%, rgba(18,15,10,.86) 0%, rgba(6,6,7,.95) 58%, rgba(3,3,4,.97) 100%);
  backdrop-filter:blur(22px);
  opacity:0;
  transition:opacity 1100ms var(--ease-veil);
}
.outro[hidden]{ display:none; }
.outro.is-shown{ opacity:1; }

.outro__inner{
  display:flex; flex-direction:column; align-items:center;
  text-align:center;
  padding:0 var(--pad-x);
  /* wide enough that the headline is never forced to break */
  max-width:min(60rem, 94vw);
}

.outro__brand{ margin-bottom:clamp(22px,3.4vh,36px); }

.outro__title{
  margin:0;
  font-family:var(--font-ar); font-weight:400;
  font-size:clamp(30px,4.4vw,68px);
  line-height:1.34;
  color:var(--ink);
  text-shadow:0 2px 50px rgba(0,0,0,.5);
}

.outro__sub{
  margin:18px 0 0;
  font-family:var(--font-ar); font-weight:300;
  font-size:clamp(14px,1.3vw,19px); line-height:2;
  color:var(--ink-dim);
  max-width:44ch;
  text-wrap:balance;         /* never leave a short orphan line */
}
/* No balancing here — it would split a headline that fits on one line. */
.outro__title{ text-wrap:pretty; }

/* The clinic's three treatment lines. Names rather than figures, so the type
   sits smaller than a numeral would and the descriptor carries the detail. */
.outro__services{
  list-style:none; margin:clamp(28px,4vh,44px) 0 0; padding:0;
  display:flex; flex-wrap:wrap; justify-content:center;
  gap:clamp(22px,3.6vw,56px);
  direction:rtl;
}
.outro__services li{
  display:flex; flex-direction:column; align-items:center; gap:8px;
  position:relative;
}
.outro__services li + li::after{
  content:""; position:absolute; top:10%; right:calc(100% + clamp(11px,1.8vw,28px));
  width:1px; height:80%; background:var(--line);
}
.outro__service-k{
  font-family:var(--font-ar); font-weight:500;
  font-size:clamp(17px,1.7vw,25px);
  color:var(--gold);
  line-height:1.1;
}
.outro__service-v{
  font-family:var(--font-ar); font-weight:300;
  font-size:clamp(11px,1vw,14px);
  color:var(--ink-faint);
  letter-spacing:.01em;
}

.outro__actions{
  margin-top:clamp(32px,4.6vh,52px);
  display:flex; gap:12px; justify-content:center; flex-wrap:wrap;
  direction:rtl;
}

.outro__btn{
  position:relative;
  padding:16px 40px;
  border:1px solid var(--line); border-radius:999px;
  overflow:hidden;
  font-family:var(--font-ar); font-weight:500; font-size:clamp(13px,1.05vw,15px);
  color:var(--ink-dim);
  transition:color 480ms var(--ease-cine), border-color 480ms var(--ease-cine),
             transform 480ms var(--ease-cine), box-shadow 480ms var(--ease-cine);
}
.outro__btn:hover{ color:var(--ink); border-color:rgba(244,241,236,.42); transform:translateY(-2px); }
.outro__btn:focus-visible{ outline:1px solid var(--sand); outline-offset:4px; }

/* Primary: the same gold fill as the splash CTA, so the two bookend each other. */
.outro__btn--solid{
  border-color:rgba(180,151,79,.55);
  color:var(--ink);
}
.outro__btn-label{ position:relative; z-index:2; }
.outro__btn-fill{
  position:absolute; inset:0; z-index:1;
  background:linear-gradient(90deg, var(--gold) 0%, var(--sand) 100%);
  transform:scaleX(0); transform-origin:right center;
  transition:transform 640ms var(--ease-cine);
}
.outro__btn--solid:hover{
  color:#141109; border-color:var(--sand);
  box-shadow:0 16px 40px -20px rgba(180,151,79,.7);
}
.outro__btn--solid:hover .outro__btn-fill{ transform:scaleX(1); }

/* Quiet tertiary action — present, but never competing. */
.outro__back{
  margin-top:clamp(18px,2.6vh,26px);
  font-family:var(--font-ar); font-size:12px;
  color:var(--ink-faint);
  border-bottom:1px solid transparent;
  transition:color 420ms var(--ease-cine), border-color 420ms var(--ease-cine);
}
.outro__back:hover{ color:var(--ink-dim); border-bottom-color:var(--line); }

@media (max-width:560px){
  .outro__services{ gap:18px; }
  .outro__services li + li::after{ display:none; }
  .outro__actions{ width:100%; flex-direction:column; }
  .outro__btn{ width:100%; }
}

/* ── Responsive ──────────────────────────────────────────────────────────── */

/* Below 16:9 the frame goes taller than wide — move the text to the lower band
   so it never collides with the subject of the shot. */
@media (max-aspect-ratio: 15/10){
  .scene__transcript.pos-middle-right,
  .scene__transcript.pos-middle-left{
    align-items:flex-end; justify-content:flex-start;
    padding-bottom:calc(var(--pad-y) + clamp(120px,20vh,200px));
  }
  .phrase{ max-width:min(18ch, 82vw); font-size:clamp(24px,5.4vw,40px); }
  .scene__glow.pos-middle-right,
  .scene__glow.pos-middle-left{
    background:linear-gradient(0deg, rgba(0,0,0,.72) 0%, rgba(0,0,0,.34) 34%, transparent 62%);
  }
}

@media (max-width: 860px){
  .controls{
    flex-direction:row;
    right:auto; left:50%; transform:translateX(-50%) translateY(14px);
    bottom:calc(var(--pad-y) + clamp(52px,8vh,80px));
  }
  body.is-playing .controls{ transform:translateX(-50%); }
  .ctrl{ width:38px; height:38px; padding:10px; }
  .hint{ display:none; }
  .audio-flag{ left:50%; transform:translateX(-50%); bottom:calc(var(--pad-y) + clamp(104px,15vh,150px)); }
  .tl-node .scene-tag__name{ display:none; }   /* the number carries it */
  .scene-tag--nav{ display:none; }
}

@media (max-width: 560px){
  .phrase{ font-size:clamp(21px,6vw,30px); line-height:1.7; }
  .logo__type i{ display:none; }
}

/* ── Cursor ───────────────────────────────────────────────────────────────
   A liquid lens above everything, never in the way of a click. The outer
   elements are positioned by JS; the morphing lives on inner elements so the
   two transforms can never overwrite each other. */

.cursor-fx{
  position:fixed; inset:0;
  z-index:60;
  pointer-events:none;
  opacity:0;
  transition:opacity 700ms var(--ease-cine);
}
.cursor-fx.is-live{ opacity:1; }

.cursor-lens,
.cursor-glow,
.cursor-core{
  position:absolute; top:0; left:0;
  will-change:transform;
}

/* ── The blur lens ─────────────────────────────────────────────────────────
   Two overlapping blobs that morph and counter-rotate, so the defocused region
   is never a circle and never repeats the same shape twice. Each is feathered
   with a radial mask, so the blur dissolves into the frame instead of ending
   on a visible edge. */

.cursor-lens{
  width:var(--lens); height:var(--lens);
  --lens:230px;
  transform-origin:50% 50%;
}

.cursor-lens span{
  position:absolute; inset:0;
  backdrop-filter:blur(13px) saturate(1.22) brightness(1.05);
  -webkit-backdrop-filter:blur(13px) saturate(1.22) brightness(1.05);
  /* the feather — without this the lens has a hard rim */
  -webkit-mask-image:radial-gradient(closest-side, #000 42%, rgba(0,0,0,.55) 68%, transparent 100%);
          mask-image:radial-gradient(closest-side, #000 42%, rgba(0,0,0,.55) 68%, transparent 100%);
}

/* Stretch and squash come from the pointer's speed, set live in JS. */
.cursor-lens__a{
  border-radius:58% 42% 47% 53% / 46% 51% 49% 54%;
  transform:scale(calc(var(--stretch,1) * 1), calc(var(--squash,1) * 1));
  animation:lensMorphA 9s ease-in-out infinite;
}
.cursor-lens__b{
  border-radius:41% 59% 63% 37% / 55% 45% 55% 45%;
  opacity:.85;
  transform:scale(calc(var(--stretch,1) * .82), calc(var(--squash,1) * .9));
  animation:lensMorphB 13s ease-in-out infinite reverse;
}

@keyframes lensMorphA{
  0%,100%{ border-radius:58% 42% 47% 53% / 46% 51% 49% 54%; rotate:0deg;   }
  33%    { border-radius:44% 56% 64% 36% / 58% 42% 58% 42%; rotate:52deg;  }
  66%    { border-radius:63% 37% 39% 61% / 41% 62% 38% 59%; rotate:-38deg; }
}
@keyframes lensMorphB{
  0%,100%{ border-radius:41% 59% 63% 37% / 55% 45% 55% 45%; rotate:0deg;   }
  40%    { border-radius:62% 38% 42% 58% / 39% 58% 42% 61%; rotate:-64deg; }
  75%    { border-radius:48% 52% 57% 43% / 62% 40% 60% 38%; rotate:41deg;  }
}

/* ── The glow ──────────────────────────────────────────────────────────────
   Warm, soft, and lifting a little as the pointer picks up speed. */

.cursor-glow{
  width:200px; height:200px;
  border-radius:50%;
  mix-blend-mode:screen;
  opacity:calc(.74 * var(--lift, 1));
  background:radial-gradient(circle,
    rgba(240,214,152,.58) 0%,
    rgba(206,175,110,.29) 34%,
    rgba(180,151,79,.11) 60%,
    rgba(180,151,79,0) 78%);
  filter:blur(6px);
  animation:glowBreathe 6s ease-in-out infinite;
}
@keyframes glowBreathe{
  0%,100%{ scale:1;     }
  50%    { scale:1.12;  }
}

/* ── The core ──────────────────────────────────────────────────────────────
   Small, bright, exactly on the pointer — so precision never feels lost. */

.cursor-core{
  width:16px; height:16px;
  border-radius:50%;
  mix-blend-mode:screen;
  background:radial-gradient(circle,
    rgba(255,248,228,.92) 0%,
    rgba(240,214,152,.48) 38%,
    rgba(240,214,152,0) 72%);
}

/* ── Motion preferences ──────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
    transition-duration:120ms !important;
  }
  .scene__video{ animation:none; }
  .grain{ animation:none; }
  .scene.is-holding .scene__frame{ animation:none; }
  .gate__motion{ display:none; }
  .caret{ transition:opacity 120ms linear; }
}
