// Avakata — brand film: "A website heals itself, overnight."
// Composes Sprites inside the animations.jsx <Stage>. Themed with site.css
// CSS variables so the Tweaks panel (accent / background / grain) restyles it live.

const C = {
  bg: 'var(--bg)',
  elev: 'var(--bg-elev)',
  line: 'var(--line-strong)',
  text: 'var(--text)',
  mute: 'var(--text-mute)',
  dim: 'var(--text-dim)',
  acc: 'var(--accent)',
  cyan: 'var(--signal-cyan)',
  amber: 'var(--signal-amber)',
  warm: 'var(--signal-warm)',
  red: 'var(--signal-red)',
  green: 'var(--signal-green)',
  serif: 'var(--f-serif)',
  sans: 'var(--f-sans)',
  mono: 'var(--f-mono)'
};

const W = 1280,H = 720;

/* ---------- shared bits ---------- */

function FilmGrid() {
  return (
    <div style={{
      position: 'absolute', inset: 0,
      backgroundImage:
      'linear-gradient(to right, rgba(232,234,237,0.05) 1px, transparent 1px),' +
      'linear-gradient(to bottom, rgba(232,234,237,0.05) 1px, transparent 1px)',
      backgroundSize: '48px 48px',
      maskImage: 'radial-gradient(ellipse 75% 70% at 50% 45%, black 30%, transparent 100%)',
      WebkitMaskImage: 'radial-gradient(ellipse 75% 70% at 50% 45%, black 30%, transparent 100%)'
    }} />);

}

function Glow({ x, y, size, color, opacity = 0.16 }) {
  return (
    <div style={{
      position: 'absolute', left: x, top: y, width: size, height: size,
      borderRadius: '50%', background: color, filter: 'blur(80px)', opacity,
      transform: 'translate(-50%,-50%)', pointerEvents: 'none'
    }} />);

}

// mono caption bar pinned bottom-center; shows whichever line is active
function Caption({ lines }) {
  const t = useTime();
  const active = lines.find((l) => t >= l[0] && t < l[1]);
  if (!active) return null;
  const localT = t - active[0];
  const fade = Math.min(1, localT / 0.4) * Math.min(1, (active[1] - t) / 0.4);
  return (
    <div style={{
      position: 'absolute', left: 0, right: 0, bottom: 54, textAlign: 'center',
      opacity: Math.max(0, fade)
    }}>
      <span style={{
        fontFamily: C.mono, fontSize: 15, letterSpacing: '0.16em', textTransform: 'uppercase',
        color: C.mute, padding: '10px 20px',
        border: '1px solid ' + C.line, borderRadius: 999,
        background: 'rgba(255,255,255,0.03)', backdropFilter: 'blur(8px)'
      }}>{active[2]}</span>
    </div>);

}

// pulsing status dot
function Dot({ color = C.acc, size = 9 }) {
  const t = useTime();
  const p = 0.5 + 0.5 * Math.sin(t * 5);
  return (
    <span style={{
      display: 'inline-block', width: size, height: size, borderRadius: '50%',
      background: color, boxShadow: `0 0 ${6 + p * 8}px ${color}`, opacity: 0.6 + 0.4 * p,
      verticalAlign: 'middle'
    }} />);

}

/* ---------- Scene 1 · cold open ---------- */

function ColdOpen() {
  const { localTime, duration } = useSprite();
  const exit = Math.max(0, duration - 0.6);
  const inP = Easing.easeOutCubic(clamp(localTime / 0.8, 0, 1));
  const outP = localTime > exit ? Easing.easeInCubic(clamp((localTime - exit) / 0.6, 0, 1)) : 0;
  const op = inP * (1 - outP);
  // clock ticking 03:39 -> 03:41
  const mins = 39 + Math.floor(localTime / 1.6);
  const secs = Math.floor(localTime * 23 % 60);
  const clock = `03:${String(Math.min(41, mins)).padStart(2, '0')}:${String(secs).padStart(2, '0')}`;
  return (
    <div style={{ position: 'absolute', inset: 0, display: 'grid', placeContent: 'center', textAlign: 'center', opacity: op }}>
      <div style={{ fontFamily: C.mono, fontSize: 16, letterSpacing: '0.3em', color: C.acc, marginBottom: 26 }}>
        {clock} · LOCAL
      </div>
      <div style={{ fontFamily: C.serif, fontSize: 92, lineHeight: 1.0, color: C.text, letterSpacing: '-0.02em' }}>
        While you sleep,
      </div>
      <div style={{ fontFamily: C.serif, fontStyle: 'italic', fontSize: 92, lineHeight: 1.05, color: C.acc, letterSpacing: '-0.02em' }}>
        your site goes to work.
      </div>
      <div style={{ fontFamily: C.mono, fontSize: 14, letterSpacing: '0.22em', textTransform: 'uppercase', color: C.dim, marginTop: 34 }}>
        no team online · no one in the loop
      </div>
    </div>);

}

/* ---------- Scene 2–4 · the engine sequence (one continuous shot) ---------- */

// product description rewrite: old strikes, new types
function RewriteBlock({ L }) {
  const OLD = 'Firm-ground soccer cleats. Synthetic upper. Molded studs. Sizes 7–13. Lightweight.';
  const NEW = 'The boot that turns your first step into your fastest. A second-skin upper welds your foot to the ball; the stud plate bites the turf and fires you forward.';
  const struck = L > 2.0;
  const typeStart = 2.4,typeDur = 3.0;
  const tp = clamp((L - typeStart) / typeDur, 0, 1);
  const shown = NEW.slice(0, Math.floor(Easing.easeInOutQuad(tp) * NEW.length));
  return (
    <div style={{ display: 'grid', gap: 12 }}>
      <div style={{
        fontFamily: C.sans, fontSize: 17, lineHeight: 1.5, color: C.mute,
        textDecoration: struck ? 'line-through' : 'none',
        opacity: struck ? 0.4 : 0.85, transition: 'opacity .4s'
      }}>{OLD}</div>
      {L > typeStart &&
      <div style={{ display: 'grid', gap: 7 }}>
          <div style={{ fontFamily: C.mono, fontSize: 11, letterSpacing: '0.14em', textTransform: 'uppercase', color: C.acc, display: 'flex', alignItems: 'center', gap: 8 }}>
            <Dot size={7} /> Engine rewrite · auto
          </div>
          <div style={{ fontFamily: C.sans, fontSize: 18, lineHeight: 1.5, color: C.text }}>
            {shown}{tp < 1 && <span style={{ color: C.acc }}>▍</span>}
          </div>
        </div>
      }
    </div>);

}

function SignalRow({ label, value, color, fill, t, delay }) {
  const p = clamp((t - delay) / 1.0, 0, 1);
  const flicker = label === 'Conversion' && t > 3 && t < 6 ? 0.6 + 0.4 * Math.sin(t * 14) : 1;
  return (
    <div style={{ display: 'grid', gridTemplateColumns: '92px 1fr 42px', alignItems: 'center', gap: 12 }}>
      <span style={{ fontFamily: C.mono, fontSize: 11, letterSpacing: '0.1em', textTransform: 'uppercase', color: C.mute }}>{label}</span>
      <span style={{ height: 6, borderRadius: 999, background: 'rgba(255,255,255,0.07)', overflow: 'hidden', position: 'relative' }}>
        <span style={{ position: 'absolute', inset: 0, width: `${fill * p}%`, background: color, borderRadius: 999, boxShadow: `0 0 10px ${color}`, opacity: flicker }} />
      </span>
      <span style={{ fontFamily: C.mono, fontSize: 11, textAlign: 'right', color: C.text }}>{value}</span>
    </div>);

}

function TrafficDots({ L }) {
  // streaming dots converging toward the page (center-left)
  const tx = 460,ty = 360; // target inside browser
  const dots = [];
  const N = 26;
  for (let i = 0; i < N; i++) {
    const seed = i * 999;
    const cycle = 3.2;
    const phase = (L + i / N * cycle) % cycle / cycle; // 0..1
    const ang = i * 137.5 * Math.PI / 180;
    const startR = 520;
    const sx = tx + Math.cos(ang) * startR * 1.4;
    const sy = ty + Math.sin(ang) * startR * 0.8;
    const e = Easing.easeInQuad(phase);
    const x = sx + (tx - sx) * e;
    const y = sy + (ty - sy) * e;
    const op = phase < 0.1 ? phase / 0.1 : phase > 0.85 ? (1 - phase) / 0.15 : 1;
    const col = i % 7 === 0 ? C.cyan : i % 11 === 0 ? C.warm : C.acc;
    dots.push(
      <div key={i} style={{
        position: 'absolute', left: x, top: y, width: 4, height: 4, borderRadius: '50%',
        background: col, opacity: op * 0.8, boxShadow: `0 0 6px ${col}`
      }} />
    );
  }
  return <div style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}>{dots}</div>;
}

function Sparkline({ p }) {
  const data = [12, 13, 13, 14, 13, 15, 19, 26, 35, 48, 64, 82, 100];
  const w = 260,h = 90;
  const max = 100,min = 10;
  const pts = data.map((v, i) => [i / (data.length - 1) * w, h - (v - min) / (max - min) * (h - 8) - 4]);
  const shownCount = Math.max(2, Math.floor(p * data.length));
  const sub = pts.slice(0, shownCount);
  const d = sub.map((pt, i) => i === 0 ? `M${pt[0]},${pt[1]}` : `L${pt[0]},${pt[1]}`).join(' ');
  const last = sub[sub.length - 1];
  return (
    <svg viewBox={`0 0 ${w} ${h}`} style={{ width: w, height: h, overflow: 'visible' }}>
      <defs>
        <linearGradient id="film-spark" x1="0" x2="0" y1="0" y2="1">
          <stop offset="0%" stopColor={C.acc} stopOpacity="0.35" />
          <stop offset="100%" stopColor={C.acc} stopOpacity="0" />
        </linearGradient>
      </defs>
      <path d={`${d} L${last[0]},${h} L0,${h} Z`} fill="url(#film-spark)" />
      <path d={d} fill="none" stroke={C.acc} strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" />
      <circle cx={last[0]} cy={last[1]} r="4" fill={C.acc} />
    </svg>);

}

function EngineSequence() {
  const { localTime: L } = useSprite();
  // window entrance
  const winP = Easing.easeOutCubic(clamp(L / 0.7, 0, 1));
  const winScale = 0.94 + 0.06 * winP;

  const showScan = L > 5.4 && L < 7.2;
  const scanY = 150 + (L - 5.4) / 1.8 * 430;
  const showAlert = L > 6.2;
  const phaseSignals = L < 9.0; // signals visible early, results later
  const resultsP = clamp((L - 9.6) / 4.0, 0, 1);
  const ship = L > 9.4;

  // counter +0 -> +186
  const liftP = Easing.easeOutCubic(clamp((L - 9.8) / 3.4, 0, 1));
  const lift = Math.floor(liftP * 186);

  return (
    <div style={{ position: 'absolute', inset: 0, opacity: winP }}>
      {/* traffic */}
      {L > 0.5 && L < 9 && <TrafficDots L={L} />}

      {/* BROWSER WINDOW */}
      <div style={{
        position: 'absolute', left: 140, top: 150, width: 640, height: 430,
        transform: `scale(${winScale})`, transformOrigin: 'center',
        background: C.elev, border: '1px solid ' + C.line, borderRadius: 16, overflow: 'hidden',
        boxShadow: '0 50px 100px -40px rgba(0,0,0,0.7)'
      }}>
        {/* chrome */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '13px 16px', borderBottom: '1px solid ' + C.line }}>
          <span style={{ width: 10, height: 10, borderRadius: '50%', background: 'rgba(255,255,255,0.18)' }} />
          <span style={{ width: 10, height: 10, borderRadius: '50%', background: 'rgba(255,255,255,0.18)' }} />
          <span style={{ width: 10, height: 10, borderRadius: '50%', background: 'rgba(255,255,255,0.18)' }} />
          <span style={{ marginLeft: 14, fontFamily: C.mono, fontSize: 12, color: C.dim, letterSpacing: '0.06em' }}>
            kickhaus.shop / vapor-strike-fg
          </span>
        </div>
        {/* page body */}
        <div style={{ display: 'grid', gridTemplateColumns: '180px 1fr', gap: 22, padding: 26 }}>
          {/* product image */}
          <div style={{
            height: 170, borderRadius: 12, border: '1px solid ' + C.line,
            background: 'radial-gradient(circle at 40% 35%, rgba(196,255,61,0.20), transparent 55%), radial-gradient(circle at 70% 75%, rgba(61,217,255,0.16), transparent 60%), linear-gradient(135deg,#16181d,#0c0d10)'
          }} />
          <div style={{ display: 'grid', gap: 6, alignContent: 'start' }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>
              <span style={{ fontFamily: C.serif, fontSize: 28, color: C.text }}>Vapor Strike FG Cleats</span>
              <span style={{ fontFamily: C.serif, fontStyle: 'italic', fontSize: 26, color: C.acc }}>$280</span>
            </div>
          </div>
          <div style={{ gridColumn: '1 / -1', marginTop: 4 }}>
            <RewriteBlock L={L} />
          </div>
        </div>

        {/* scan line */}
        {showScan &&
        <div style={{ position: 'absolute', left: 0, right: 0, top: scanY - 150, height: 2, background: C.acc, boxShadow: `0 0 16px ${C.acc}`, opacity: 0.8 }} />
        }
      </div>

      {/* RIGHT PANEL — signals -> results */}
      <div style={{ position: 'absolute', left: 830, top: 178, width: 310 }}>
        {/* alert chip */}
        {showAlert &&
        <div style={{
          marginBottom: 16, padding: '14px 16px', borderRadius: 12,
          border: '1px solid ' + C.line, background: 'linear-gradient(135deg, rgba(196,255,61,0.10), rgba(61,217,255,0.04))',
          opacity: clamp((L - 6.2) / 0.5, 0, 1)
        }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 9, fontFamily: C.mono, fontSize: 11, letterSpacing: '0.14em', textTransform: 'uppercase', color: C.acc }}>
              <Dot size={7} /> Self-heal triggered
            </div>
            <div style={{ fontFamily: C.sans, fontSize: 13.5, color: C.text, marginTop: 7, lineHeight: 1.45 }}>
              High CTR, low conversion. Rewriting product copy.
            </div>
          </div>
        }

        {/* signals */}
        {phaseSignals &&
        <div style={{ display: 'grid', gap: 14, padding: 20, borderRadius: 14, border: '1px solid ' + C.line, background: C.elev, opacity: clamp((L - 1.2) / 0.6, 0, 1) * (L > 8.2 ? clamp((9 - L) / 0.8, 0, 1) : 1) }}>
            <div style={{ fontFamily: C.mono, fontSize: 11, letterSpacing: '0.16em', textTransform: 'uppercase', color: C.mute }}>Live signals</div>
            <SignalRow label="Click-thru" value="High" color={C.green} fill={84} t={L} delay={1.4} />
            <SignalRow label="Add to cart" value="Mid" color={C.amber} fill={52} t={L} delay={1.8} />
            <SignalRow label="Conversion" value="Low" color={C.red} fill={22} t={L} delay={2.2} />
          </div>
        }

        {/* results */}
        {ship &&
        <div style={{ display: 'grid', gap: 16, opacity: clamp((L - 9.6) / 0.6, 0, 1) }}>
            <div style={{ padding: '12px 16px', borderRadius: 12, border: '1px solid ' + C.line, background: C.elev, display: 'flex', alignItems: 'center', gap: 10 }}>
              <Dot size={7} color={C.cyan} />
              <span style={{ fontFamily: C.mono, fontSize: 11.5, letterSpacing: '0.08em', color: C.mute }}>
                Variant live · <b style={{ color: C.text }}>18%</b> · critic gate <b style={{ color: C.acc }}>passed</b>
              </span>
            </div>
            <div style={{ padding: 20, borderRadius: 14, border: '1px solid ' + C.line, background: C.elev, display: 'grid', gap: 10 }}>
              <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between' }}>
                <span style={{ fontFamily: C.serif, fontStyle: 'italic', fontSize: 52, color: C.acc, lineHeight: 1 }}>+{lift}%</span>
                <span style={{ fontFamily: C.mono, fontSize: 10.5, letterSpacing: '0.12em', textTransform: 'uppercase', color: C.dim, textAlign: 'right' }}>conversion<br />48h since rewrite</span>
              </div>
              <Sparkline p={resultsP} />
            </div>
          </div>
        }
      </div>
    </div>);

}

/* ---------- Scene 5 · outro ---------- */

function Outro() {
  const { localTime, duration } = useSprite();
  const inP = Easing.easeOutCubic(clamp(localTime / 0.9, 0, 1));
  const exit = Math.max(0, duration - 0.5);
  const outP = localTime > exit ? clamp((localTime - exit) / 0.5, 0, 1) : 0;
  const op = inP * (1 - outP);
  const y = (1 - inP) * 18;
  return (
    <div style={{ position: 'absolute', inset: 0, display: 'grid', placeContent: 'center', textAlign: 'center', opacity: op, transform: `translateY(${y}px)` }}>
      <div style={{ fontFamily: C.serif, fontSize: 78, lineHeight: 1.05, color: C.text, letterSpacing: '-0.02em' }}>
        Websites that <span style={{ fontStyle: 'italic', color: C.acc }}>get better</span>
      </div>
      <div style={{ fontFamily: C.serif, fontSize: 78, lineHeight: 1.05, color: C.text, letterSpacing: '-0.02em', marginBottom: 40 }}>
        on their own.
      </div>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 14 }}>
        <span style={{ fontFamily: C.mono, fontWeight: 600, fontSize: 22, letterSpacing: '0.32em', color: C.text }}>AVAKATA</span>
      </div>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 9, marginTop: 18, fontFamily: C.mono, fontSize: 12, letterSpacing: '0.18em', textTransform: 'uppercase', color: C.mute }}>
        <Dot size={7} color={C.green} /> system status · healthy
      </div>
    </div>);

}

/* ---------- root ---------- */

function Film() {
  return (
    <Stage width={W} height={H} duration={27} background={C.bg} persistKey="avakata-film">
      <FilmGrid />
      <Glow x={250} y={180} size={520} color={C.acc} opacity={0.10} />
      <Glow x={1050} y={560} size={460} color={C.cyan} opacity={0.08} />

      <Sprite start={0} end={4.6}><ColdOpen /></Sprite>
      <Sprite start={4.2} end={22.8}><EngineSequence /></Sprite>
      <Sprite start={22.5} end={27}><Outro /></Sprite>

      <Caption lines={[
      [5.0, 9.2, 'Traffic arrives · the engine watches'],
      [9.2, 12.0, 'It finds the friction · rewrites the copy'],
      [12.0, 16.0, 'Ships the variant · passes its own critic'],
      [16.0, 21.5, 'Measures what wins · keeps it · logs it']]
      } />
    </Stage>);

}

ReactDOM.createRoot(document.getElementById('film-root')).render(<Film />);