/* global React, Icon, Logo, Mark, Button, Tag, Eyebrow */
const { useState: uS, useEffect: uE, useRef: uRef } = React;

const PAD_X = 'clamp(22px, 5.5vw, 76px)';
const SEC_Y = 'clamp(72px, 11vw, 128px)';

// Step-snap for the pinned scroll-scrub sections, as a DIRECTION-based pager
// (TikTok-style): after scrolling pauses, any deliberate swipe past a small
// deadzone commits one step in that direction, so a light flick always advances
// instead of rounding back to the same card. Larger drags move proportionally.
// Scoped per-section; edges are left un-snapped so they hand off to neighbors.
function attachStepSnap(secRef, pages) {
  if (pages < 2) return () => {};
  const clamp = (v, a, b) => Math.min(b, Math.max(a, v));
  const DEADZONE = 0.1; // fraction of a page that counts as a deliberate swipe
  let timer = 0, snapping = false, current = 0;
  const snap = () => {
    const sec = secRef.current; if (!sec) return;
    const totalPx = sec.offsetHeight - window.innerHeight; if (totalPx <= 0) return;
    const top = sec.getBoundingClientRect().top;
    const p = -top / totalPx;
    if (p <= 0.004 || p >= 0.996) { current = clamp(Math.round(p * (pages - 1)), 0, pages - 1); return; }
    const pos = p * (pages - 1);
    const delta = pos - current;
    const target = Math.abs(delta) <= DEADZONE
      ? current
      : clamp(current + Math.sign(delta) * Math.max(1, Math.round(Math.abs(delta))), 0, pages - 1);
    current = target;
    const per = totalPx / (pages - 1);
    const delPx = (target * per) - (-top);
    if (Math.abs(delPx) < 2) return;
    snapping = true;
    window.scrollBy({ top: delPx, behavior: 'smooth' });
    setTimeout(() => { snapping = false; }, 560);
  };
  const onScroll = () => { if (snapping) return; clearTimeout(timer); timer = setTimeout(snap, 110); };
  window.addEventListener('scroll', onScroll, { passive: true });
  return () => { clearTimeout(timer); window.removeEventListener('scroll', onScroll); };
}

/* ============================ HERO ============================ */
function Hero({ t, motionOn, bg, theme }) {
  const secRef = uRef(null);
  const markRef = uRef(null);
  const spotRef = uRef(null);
  const bloomRef = uRef(null);
  const eyebrowRef = uRef(null);
  const bigRef = uRef(null);
  const shortRef = uRef(null);
  const ledeRef = uRef(null);
  const btnRef = uRef(null);
  const scrollHintRef = uRef(null);
  const mouse = uRef({ px: 0, py: 0 });
  const [mounted, setMounted] = uS(false);
  const choreo = !window.REDUCED;

  uE(() => {const id = setTimeout(() => setMounted(true), 80);return () => clearTimeout(id);}, []);

  // cursor spotlight + mark drift (pointer)
  uE(() => {
    if (!motionOn) return;
    const sec = secRef.current;if (!sec) return;
    const onMove = (e) => {
      const r = sec.getBoundingClientRect();
      const x = e.clientX - r.left,y = e.clientY - r.top;
      mouse.current = { px: x / r.width - 0.5, py: y / r.height - 0.5 };
      if (spotRef.current) {spotRef.current.style.background = `radial-gradient(560px circle at ${x}px ${y}px, rgba(212,175,55,0.16), transparent 60%)`;}
    };
    sec.addEventListener('mousemove', onMove);
    return () => sec.removeEventListener('mousemove', onMove);
  }, [motionOn]);

  // scroll-driven hero choreography: the hero is a tall scroll track with a
  // pinned stage. As you scroll: the eyebrow fades + shrinks first, the big
  // 3-line title grows into that space, then shrinks and cross-fades into a
  // single-line title while the lede + buttons rise in beneath it.
  // Driven by BOTH a rAF loop and scroll/input listeners so it stays locked to
  // the scroll position no matter how the host dispatches scrolling.
  uE(() => {
    if (!choreo) return;
    let raf = 0, lastP = -1, lastMx = 9, lastMy = 9, alive = true;
    const clamp = (v, a, b) => Math.min(b, Math.max(a, v));
    const lerp = (a, b, t) => a + (b - a) * t;
    const seg = (p, a, b) => clamp((p - a) / (b - a), 0, 1);
    const apply = () => {
      const sec = secRef.current; if (!sec) return;
      const total = Math.max(1, sec.offsetHeight - window.innerHeight);
      const p = clamp(-sec.getBoundingClientRect().top / total, 0, 1);
      const { px, py } = mouse.current;
      if (p === lastP && px === lastMx && py === lastMy) return;
      lastP = p; lastMx = px; lastMy = py;
      const e = seg(p, 0, 0.16);
      if (eyebrowRef.current) {
        eyebrowRef.current.style.opacity = String(1 - e);
        eyebrowRef.current.style.transform = `translateY(${-e * 26}px) scale(${lerp(1, 0.7, e)})`;
      }
      const g = seg(p, 0, 0.30), s = seg(p, 0.30, 0.52);
      if (bigRef.current) {
        bigRef.current.style.opacity = String(1 - s);
        bigRef.current.style.transform = `translateY(${-g * 20}px) scale(${lerp(1, 1.08, g) * lerp(1, 0.42, s)})`;
        bigRef.current.style.filter = `blur(${lerp(0, 6, s)}px)`;
      }
      const sh = seg(p, 0.44, 0.66);
      if (shortRef.current) {
        shortRef.current.style.opacity = String(sh);
        shortRef.current.style.transform = `scale(${lerp(0.62, 1, sh)})`;
        shortRef.current.style.filter = `blur(${lerp(6, 0, sh)}px)`;
        shortRef.current.style.pointerEvents = sh > 0.5 ? 'auto' : 'none';
      }
      const l = seg(p, 0.62, 0.82);
      if (ledeRef.current) {
        ledeRef.current.style.opacity = String(l);
        ledeRef.current.style.transform = `translateY(${lerp(22, 0, l)}px)`;
        ledeRef.current.style.pointerEvents = l > 0.5 ? 'auto' : 'none';
      }
      const b = seg(p, 0.74, 0.94);
      if (btnRef.current) {
        btnRef.current.style.opacity = String(b);
        btnRef.current.style.transform = `translateY(${lerp(16, 0, b)}px)`;
        btnRef.current.style.pointerEvents = b > 0.5 ? 'auto' : 'none';
      }
      if (markRef.current) {
        markRef.current.style.transform = `translateY(calc(-50% + ${p * 120 + (motionOn ? py * -26 : 0)}px)) translateX(${motionOn ? px * -26 : 0}px) rotate(${motionOn ? px * 4 : 0}deg) scale(${1 + p * 0.08})`;
      }
      if (bloomRef.current) bloomRef.current.style.transform = `translateY(${p * 60}px)`;
      if (scrollHintRef.current) scrollHintRef.current.style.opacity = String(1 - seg(p, 0, 0.1));
    };
    const loop = () => { apply(); if (alive) raf = requestAnimationFrame(loop); };
    raf = requestAnimationFrame(loop);
    const onEvt = () => apply();
    const opts = { passive: true };
    window.addEventListener('scroll', onEvt, opts);
    window.addEventListener('wheel', onEvt, opts);
    window.addEventListener('touchmove', onEvt, opts);
    window.addEventListener('resize', onEvt, opts);
    document.addEventListener('scroll', onEvt, opts);
    apply();
    return () => {
      alive = false; cancelAnimationFrame(raf);
      window.removeEventListener('scroll', onEvt); window.removeEventListener('wheel', onEvt);
      window.removeEventListener('touchmove', onEvt); window.removeEventListener('resize', onEvt);
      document.removeEventListener('scroll', onEvt);
    };
  }, [motionOn, choreo]);

  const line = (txt, i, accent) =>
  <div style={{ overflow: 'hidden', display: 'block' }}>
      <span style={{
      display: 'inline-block', color: accent ? 'var(--accent)' : 'inherit',
      transform: mounted ? 'translateY(0)' : 'translateY(108%)',
      transition: `transform 920ms var(--ease-out) ${120 + i * 110}ms`
    }}>{txt}</span>
    </div>;


  const markStyle = theme === 'light'
    ? { width: '100%', opacity: 0.08, filter: 'brightness(0)' }
    : { width: '100%', opacity: 0.05 };

  return (
    <section id="home" data-screen-label="Home / Početna" ref={secRef} style={{
      position: 'relative', height: choreo ? '230vh' : '100svh', background: 'var(--bg)',
    }}>
      <div style={{
        position: choreo ? 'sticky' : 'relative', top: 0, height: '100svh', overflow: 'hidden',
        display: 'flex', flexDirection: 'column', justifyContent: 'center',
        padding: `clamp(108px,13vh,170px) ${PAD_X} clamp(64px,9vh,104px)`,
      }}>
        {/* mark watermark */}
        {bg !== 'minimal' &&
        <div ref={markRef} style={{ position: 'absolute', right: '-6%', top: '50%', width: 'min(58vw, 720px)', transform: 'translateY(-50%)', pointerEvents: 'none', willChange: 'transform' }}>
            <Mark size="100%" style={markStyle} />
          </div>
        }
        {/* static gold bloom + cursor spotlight */}
        <div ref={bloomRef} style={{ position: 'absolute', top: '-18%', right: '-10%', width: 680, height: 680, background: 'radial-gradient(circle, var(--gold-soft), transparent 62%)', pointerEvents: 'none', willChange: 'transform' }} />
        {bg === 'spotlight' && motionOn && <div ref={spotRef} style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }} />}

        <div style={{ position: 'relative', maxWidth: 1000, width: '100%' }} data-comment-anchor="34331bb1fb-div-88-7">
          <div ref={eyebrowRef} style={{ transformOrigin: 'left center', willChange: 'transform, opacity', opacity: mounted ? 1 : 0, transition: choreo ? 'none' : 'opacity 700ms ease 80ms' }}>
            <Eyebrow style={{ marginBottom: 'clamp(20px,3vw,30px)' }}>{t.hero.eyebrow}</Eyebrow>
          </div>

          {/* title zone — big 3-line + single-line stacked in one cell */}
          <div style={{ display: 'grid', marginBottom: 'clamp(22px,3vw,34px)' }}>
            <h1 ref={bigRef} style={{
              gridArea: '1 / 1', margin: 0, fontFamily: 'var(--font-display)', fontWeight: 900, textTransform: 'uppercase',
              fontSize: 'clamp(38px, min(10vw, 15vh), 116px)', lineHeight: 0.9, letterSpacing: '-0.035em',
              color: 'var(--fg1)', transformOrigin: 'left center', transition: 'none', willChange: 'transform, opacity, filter',
            }}>
              {line(t.hero.line1, 0)}
              {line(t.hero.line2, 1)}
              {line(t.hero.line3, 2, true)}
            </h1>
            <h1 ref={shortRef} style={{
              gridArea: '1 / 1', alignSelf: 'center', justifySelf: 'start', margin: 0,
              fontFamily: 'var(--font-display)', fontWeight: 900, textTransform: 'uppercase', whiteSpace: 'nowrap',
              fontSize: 'clamp(34px, min(8vw, 12.5vh), 98px)', lineHeight: 0.95, letterSpacing: '-0.035em',
              color: 'var(--fg1)', transformOrigin: 'left center', transition: 'none', opacity: 0, pointerEvents: 'none',
            }}>{t.hero.titleShort}</h1>
          </div>

          <p ref={ledeRef} className="es-lede" style={{
            maxWidth: 560, margin: '0 0 clamp(28px,4vw,40px)', fontSize: 'clamp(17px,2.2vw,23px)',
            opacity: choreo ? 0 : (mounted ? 1 : 0), pointerEvents: choreo ? 'none' : 'auto',
            transform: !choreo && !mounted ? 'translateY(16px)' : 'translateY(0)',
            transition: choreo ? 'none' : 'opacity 800ms ease 460ms, transform 800ms var(--ease-out) 460ms',
          }}>{t.hero.lede}</p>

          <div ref={btnRef} style={{
            display: 'flex', gap: 'clamp(12px,1.6vw,16px)', flexWrap: 'wrap',
            opacity: choreo ? 0 : (mounted ? 1 : 0), pointerEvents: choreo ? 'none' : 'auto',
            transition: choreo ? 'none' : 'opacity 800ms ease 620ms',
          }}>
            <Button icon="arrow-right" onClick={() => document.getElementById('projects')?.scrollIntoView({ behavior: 'smooth' })}>{t.cta.explore}</Button>
            <Button variant="secondary" icon="play" onClick={() => document.getElementById('contact')?.scrollIntoView({ behavior: 'smooth' })}>{t.cta.reel}</Button>
          </div>
        </div>

        {/* scroll hint */}
        <div ref={scrollHintRef} style={{ position: 'absolute', left: PAD_X, bottom: 'clamp(64px,9vh,96px)', display: 'flex', alignItems: 'center', gap: 12, pointerEvents: 'none', opacity: mounted ? 1 : 0, transition: 'opacity 900ms ease 820ms' }}>
          <span style={{ fontFamily: 'var(--font-mono)', fontSize: 11, letterSpacing: '0.22em', textTransform: 'uppercase', color: 'var(--fg3)' }}>{t.hero.scroll}</span>
          <span className="es-scrolldot" style={{ width: 22, height: 34, borderRadius: 999, border: '1px solid var(--hairline-strong)', position: 'relative', flex: '0 0 auto' }}>
            <span style={{ position: 'absolute', left: '50%', top: 7, width: 3, height: 7, marginLeft: -1.5, borderRadius: 999, background: 'var(--accent)' }} />
          </span>
        </div>

        {/* running ticker */}
        <div style={{ position: 'absolute', bottom: 0, left: 0, right: 0, borderTop: '1px solid var(--hairline)', padding: '14px 0', overflow: 'hidden', maskImage: 'linear-gradient(to right, transparent, #000 8%, #000 92%, transparent)', WebkitMaskImage: 'linear-gradient(to right, transparent, #000 8%, #000 92%, transparent)' }}>
          <div className="es-marquee" style={{ display: 'inline-flex', gap: 0, whiteSpace: 'nowrap', animationPlayState: motionOn ? 'running' : 'paused' }}>
            {[0, 1].map((rep) =>
            <span key={rep} style={{ display: 'inline-flex', alignItems: 'center' }}>
                {t.hero.ticker.map((w, i) =>
              <span key={i} style={{ display: 'inline-flex', alignItems: 'center' }}>
                    <span style={{ fontFamily: 'var(--font-display)', fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.14em', fontSize: 13, color: 'var(--fg2)', padding: '0 26px' }}>{w}</span>
                    <span style={{ width: 5, height: 5, borderRadius: '50%', background: 'var(--accent)' }} />
                  </span>
              )}
              </span>
            )}
          </div>
        </div>
      </div>
    </section>);

}

/* ============================ ABOUT ============================ */
function About({ t }) {
  return (
    <section id="about" data-screen-label="About / O nama" style={{ padding: `${SEC_Y} ${PAD_X}`, background: 'var(--bg)' }}>
      <div style={{ maxWidth: 1200, margin: '0 auto' }}>
        <Reveal y={18}><Eyebrow style={{ marginBottom: 14 }}>{t.about.kicker}</Eyebrow></Reveal>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 360px), 1fr))', gap: 'clamp(28px,5vw,72px)', alignItems: 'start' }}>
          <div>
            <Reveal as="h2" className="es-display" blur delay={60} style={{ fontSize: 'clamp(40px,7vw,84px)', margin: '0 0 22px' }}>{t.about.title}</Reveal>
            <Reveal as="p" className="es-lede" delay={160} style={{ fontSize: 'clamp(19px,2.4vw,26px)', margin: 0, color: 'var(--fg1)' }}>{t.about.lede}</Reveal>
          </div>
          <div>
            <Reveal as="p" className="es-body" delay={120} style={{ fontSize: 'clamp(15px,1.8vw,17px)', lineHeight: 1.7, color: 'var(--fg2)', margin: '0 0 32px' }}>{t.about.body}</Reveal>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 22 }}>
              {t.about.points.map(([h, d], i) =>
              <Reveal key={i} delay={200 + i * 90} y={22} style={{ display: 'flex', gap: 16, alignItems: 'flex-start' }}>
                  <span style={{ fontFamily: 'var(--font-mono)', fontSize: 13, color: 'var(--accent-ink)', paddingTop: 3, flex: '0 0 auto' }}>{String(i + 1).padStart(2, '0')}</span>
                  <div>
                    <div style={{ fontFamily: 'var(--font-display)', fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.04em', fontSize: 16, color: 'var(--fg1)', marginBottom: 5 }}>{h}</div>
                    <div className="es-small" style={{ color: 'var(--fg2)' }}>{d}</div>
                  </div>
                </Reveal>
              )}
            </div>
          </div>
        </div>
      </div>
    </section>);

}

function StatItem({ n, l, i }) {
  const [ref, shown] = useReveal({ threshold: 0.4 });
  const val = useCountUp(n, shown);
  return (
    <div ref={ref} style={{
      opacity: shown ? 1 : 0, transform: shown ? 'translateY(0)' : 'translateY(24px)',
      transition: `opacity 700ms var(--ease-out) ${i * 110}ms, transform 700ms var(--ease-out) ${i * 110}ms`
    }}>
      <div style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 'clamp(48px,7vw,72px)', lineHeight: 1, color: 'var(--accent)', letterSpacing: '-0.03em', fontVariantNumeric: 'tabular-nums' }}>{val}</div>
      <div className="es-small" style={{ color: 'var(--fg2)', marginTop: 10 }}>{l}</div>
    </div>);

}

function StatsBand({ t }) {
  return (
    <section style={{ padding: `clamp(48px,7vw,72px) ${PAD_X}`, borderTop: '1px solid var(--hairline)', borderBottom: '1px solid var(--hairline)', background: 'var(--bg-sunken)' }}>
      <div style={{ maxWidth: 1200, margin: '0 auto', display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 200px), 1fr))', gap: 'clamp(24px,4vw,40px)' }}>
        {t.about.stats.map(([n, l], i) => <StatItem key={i} n={n} l={l} i={i} />)}
      </div>
    </section>);

}

/* ============================ SERVICES ============================ */
function Services({ t }) {
  const reduced = window.REDUCED;
  const [mobile, setMobile] = uS(() => typeof window !== 'undefined' && window.matchMedia('(max-width: 767px)').matches);
  uE(() => {
    const mq = window.matchMedia('(max-width: 767px)');
    const on = () => setMobile(mq.matches);
    mq.addEventListener('change', on); on();
    return () => mq.removeEventListener('change', on);
  }, []);

  // Mobile: pinned header + cards rotating two at a time (like Projects).
  if (mobile && !reduced) return <ServicesPinned t={t} />;

  // Desktop / reduced-motion: the full grid.
  return (
    <section id="services" data-screen-label="Services / Usluge" style={{ padding: `${SEC_Y} ${PAD_X}`, background: 'var(--bg)' }}>
      <div style={{ maxWidth: 1200, margin: '0 auto' }}>
        <SectionHead t={t} kicker={t.services.kicker} title={t.services.title} lede={t.services.lede} />
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 300px), 1fr))', gap: 'clamp(14px,1.6vw,20px)' }}>
          {t.services.items.map(([icon, title, desc], i) => <Reveal key={i} delay={i * 80} y={30} style={{ height: '100%' }}><ServiceCard icon={icon} title={title} desc={desc} /></Reveal>)}
        </div>
      </div>
    </section>);

}

// Mobile-only: pinned section, header fixed in view, service cards rotate 2 at a
// time on scroll (same scroll-scrub technique as the hero / projects).
function ServicesPinned({ t }) {
  const items = t.services.items;
  const groups = [];
  for (let i = 0; i < items.length; i += 2) groups.push(items.slice(i, i + 2));
  const P = groups.length;
  const secRef = uRef(null);
  const pageRefs = uRef([]);
  const counterRef = uRef(null);

  uE(() => {
    let raf = 0, alive = true, lastP = -1;
    const clamp = (v, a, b) => Math.min(b, Math.max(a, v));
    const apply = () => {
      const sec = secRef.current; if (!sec) return;
      const total = Math.max(1, sec.offsetHeight - window.innerHeight);
      const p = clamp(-sec.getBoundingClientRect().top / total, 0, 1);
      if (p === lastP) return; lastP = p;
      const pos = p * (P - 1);
      pageRefs.current.forEach((el, i) => {
        if (!el) return;
        const off = i - pos;
        const a = clamp(1 - Math.abs(off) * 1.8, 0, 1);
        el.style.opacity = String(a);
        el.style.transform = `translateY(${off * 7}vh) scale(${0.96 + 0.04 * a})`;
        el.style.filter = `blur(${Math.min(6, Math.abs(off) * 8)}px)`;
        el.style.pointerEvents = Math.abs(off) < 0.5 ? 'auto' : 'none';
        el.style.zIndex = Math.abs(off) < 0.5 ? 3 : 1;
      });
      const idx = clamp(Math.round(pos), 0, P - 1);
      if (counterRef.current) counterRef.current.textContent = String(idx + 1).padStart(2, '0');
    };
    const loop = () => { apply(); if (alive) raf = requestAnimationFrame(loop); };
    const onEvt = () => apply();
    raf = requestAnimationFrame(loop);
    ['scroll', 'wheel', 'touchmove', 'resize'].forEach((e) => window.addEventListener(e, onEvt, { passive: true }));
    const detachSnap = attachStepSnap(secRef, P);
    apply();
    return () => { alive = false; cancelAnimationFrame(raf); detachSnap(); ['scroll', 'wheel', 'touchmove', 'resize'].forEach((e) => window.removeEventListener(e, onEvt)); };
  }, [P]);

  return (
    <section id="services" data-screen-label="Services / Usluge" ref={secRef} style={{ position: 'relative', height: `${P * 92}vh`, background: 'var(--bg)' }}>
      <div style={{ position: 'sticky', top: 0, height: '100svh', overflow: 'hidden', display: 'flex', flexDirection: 'column', padding: `clamp(92px,13vh,128px) ${PAD_X} clamp(28px,5vh,52px)` }}>
        {/* header stays in view */}
        <div style={{ flex: '0 0 auto', marginBottom: 'clamp(18px,3vh,30px)' }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 16 }}>
            <Eyebrow>{t.services.kicker}</Eyebrow>
            <div className="es-caption" style={{ color: 'var(--fg3)', fontSize: 12, paddingTop: 2, flex: '0 0 auto' }}>
              <span ref={counterRef} style={{ color: 'var(--accent-ink)' }}>01</span> / {String(P).padStart(2, '0')}
            </div>
          </div>
          <h2 className="es-display" style={{ fontSize: 'clamp(32px,9vw,52px)', margin: '10px 0 10px' }}>{t.services.title}</h2>
          <p className="es-small" style={{ color: 'var(--fg2)', margin: 0, maxWidth: 520 }}>{t.services.lede}</p>
        </div>
        {/* rotating pages of 2 cards */}
        <div style={{ position: 'relative', flex: 1 }}>
          {groups.map((g, i) =>
          <div key={i} ref={(el) => pageRefs.current[i] = el} style={{ position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column', justifyContent: 'center', gap: 'clamp(12px,2vh,18px)', opacity: i === 0 ? 1 : 0, willChange: 'opacity, transform, filter' }}>
            {g.map(([icon, title, desc], j) => <div key={j}><ServiceCard icon={icon} title={title} desc={desc} /></div>)}
          </div>)}
        </div>
      </div>
    </section>);

}

function ServiceCard({ icon, title, desc }) {
  const [h, setH] = uS(false);
  return (
    <article onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)} style={{
      padding: 'clamp(24px,3vw,34px)', borderRadius: 'var(--r-md)', background: 'var(--bg-raised)',
      border: h ? '1px solid var(--accent)' : '1px solid var(--hairline)', cursor: 'default',
      transition: 'all var(--dur-base) var(--ease-out)', transform: h ? 'translateY(-4px)' : 'none',
      boxShadow: h ? 'var(--shadow-md)' : 'none', position: 'relative', overflow: 'hidden', width: '100%', height: '100%'
    }}>
      <div style={{ width: 48, height: 48, borderRadius: 'var(--r-sm)', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', background: h ? 'var(--accent)' : 'var(--bg-sunken)', color: h ? 'var(--accent-contrast)' : 'var(--accent-ink)', marginBottom: 22, transition: 'all var(--dur-base) var(--ease-out)' }}>
        <Icon name={icon} size={24} />
      </div>
      <h3 style={{ fontFamily: 'var(--font-display)', fontWeight: 800, textTransform: 'uppercase', fontSize: 21, letterSpacing: '-0.01em', margin: '0 0 12px', color: 'var(--fg1)' }}>{title}</h3>
      <p className="es-small" style={{ color: 'var(--fg2)', lineHeight: 1.6, margin: 0 }}>{desc}</p>
    </article>);

}

/* ============================ PROJECTS ============================ */
// A project is "playable" if we can open something: a specific YouTube video,
// a self-hosted file, or (fallback) an external channel link in a new tab.
function projectPlayable(s) { return !!(s.youtube || s.video || s.link); }

// Lightbox: YouTube embed or self-hosted <video>. Closes on backdrop click / Esc.
function VideoModal({ project, onClose }) {
  uE(() => {
    const onKey = (e) => { if (e.key === 'Escape') onClose(); };
    document.addEventListener('keydown', onKey);
    document.body.style.overflow = 'hidden';
    return () => { document.removeEventListener('keydown', onKey); document.body.style.overflow = ''; };
  }, []);
  return (
    <div onClick={onClose} style={{ position: 'fixed', inset: 0, zIndex: 90, background: 'rgba(0,0,0,0.86)', backdropFilter: 'blur(8px)', WebkitBackdropFilter: 'blur(8px)', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 'clamp(16px,4vw,48px)' }}>
      <div onClick={(e) => e.stopPropagation()} style={{ position: 'relative', width: 'min(1100px, 100%)', aspectRatio: '16 / 9', background: '#000', borderRadius: 'var(--r-lg)', overflow: 'hidden', boxShadow: 'var(--shadow-lg)' }}>
        {project.youtube
          ? <iframe src={`https://www.youtube.com/embed/${project.youtube}?autoplay=1&rel=0&modestbranding=1`} title={project.title} allow="autoplay; encrypted-media; picture-in-picture; fullscreen" allowFullScreen style={{ width: '100%', height: '100%', border: 0 }} />
          : <video src={project.video} controls autoPlay playsInline style={{ width: '100%', height: '100%', display: 'block' }} />}
      </div>
      <button onClick={onClose} aria-label="Close" style={{ position: 'fixed', top: 'clamp(16px,3vw,28px)', right: 'clamp(16px,3vw,28px)', width: 46, height: 46, borderRadius: 'var(--r-pill)', border: '1px solid var(--hairline-strong)', background: 'rgba(0,0,0,0.45)', color: 'var(--off-white)', cursor: 'pointer', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', zIndex: 91 }}>
        <Icon name="x" size={22} />
      </button>
    </div>);
}

// The 16:9 media block (poster/loop stand-in) with tag + play affordance.
function ProjectMedia({ s, onPlay, hovered }) {
  const playable = projectPlayable(s);
  return (
    <div onClick={playable ? onPlay : undefined} style={{
      position: 'relative', width: '100%', aspectRatio: '16 / 9', borderRadius: 'var(--r-lg)', overflow: 'hidden',
      background: s.grad, border: '1px solid var(--hairline)', boxShadow: 'var(--shadow-lg)', cursor: playable ? 'pointer' : 'default',
    }}>
      {/* TODO: swap this <img> poster for a muted autoplay <video> loop when clips land */}
      {s.img && <img src={s.img} alt="" loading="lazy" style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover', transition: 'transform var(--dur-slow) var(--ease-out)', transform: hovered ? 'scale(1.04)' : 'scale(1)' }} />}
      <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(to top, rgba(20,21,25,0.55), transparent 60%)' }} />
      <div style={{ position: 'absolute', top: 16, left: 16 }}><Tag tone={s.youtube || s.link ? 'solid' : 'dark'}>{s.tag}</Tag></div>
      {playable &&
      <div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', pointerEvents: 'none' }}>
        <span style={{ width: 'clamp(58px,7vw,84px)', height: 'clamp(58px,7vw,84px)', borderRadius: '50%', background: 'var(--accent)', color: 'var(--accent-contrast)', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', boxShadow: 'var(--shadow-gold)', transform: hovered ? 'scale(1.06)' : 'scale(1)', transition: 'transform var(--dur-base) var(--ease-out)' }}>
          <Icon name="play" size={30} />
        </span>
      </div>}
    </div>);
}

// One project's content (meta + media). Shared by the pinned stage and the
// mobile/reduced-motion stacked fallback.
function ProjectPane({ s, idx, total, onPlay }) {
  const [h, setH] = uS(false);
  const playable = projectPlayable(s);
  return (
    <div className="proj-pane" onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
      style={{ width: '100%', maxWidth: 1200, margin: '0 auto', padding: `0 ${PAD_X}`, display: 'grid', gap: 'clamp(24px,4vw,56px)', alignItems: 'center' }}>
      <div>
        <div className="es-caption" style={{ color: 'var(--accent-ink)', marginBottom: 14 }}>
          <span style={{ fontFamily: 'var(--font-mono)' }}>{String(idx + 1).padStart(2, '0')}</span> / {String(total).padStart(2, '0')} · {s.genre}
        </div>
        <h3 style={{ fontFamily: 'var(--font-display)', fontWeight: 900, textTransform: 'uppercase', fontSize: 'clamp(34px,5.5vw,68px)', letterSpacing: '-0.03em', lineHeight: 0.98, margin: '0 0 18px', color: 'var(--fg1)' }}>{s.title}</h3>
        <p className="es-lede" style={{ fontSize: 'clamp(16px,2vw,21px)', maxWidth: 460, margin: '0 0 28px' }}>{s.logline}</p>
        {playable
          ? <Button icon="play" onClick={onPlay}>{window.__ES_REEL || 'Gledaj'}</Button>
          : <span className="es-caption" style={{ color: 'var(--fg3)' }}>{s.tag}</span>}
      </div>
      <ProjectMedia s={s} onPlay={onPlay} hovered={h} />
    </div>);
}

function ProjectsShowcase({ t, onPlay }) {
  const slate = t.projects.slate;
  const N = slate.length;
  const secRef = uRef(null);
  const paneRefs = uRef([]);
  const railRef = uRef([]);
  const counterRef = uRef(null);

  // Pinned scroll-scrub on every size (same technique as the hero, which is
  // smooth on mobile). Only prefers-reduced-motion falls back to a plain list.
  const reduced = window.REDUCED;

  // expose the "watch" label for the pane button (copy lives in i18n)
  window.__ES_REEL = t.cta.reel;

  // pinned choreography: scroll progress -> which pane is centered
  uE(() => {
    if (reduced) return;
    let raf = 0, alive = true, lastP = -1;
    const clamp = (v, a, b) => Math.min(b, Math.max(a, v));
    const apply = () => {
      const sec = secRef.current; if (!sec) return;
      const total = Math.max(1, sec.offsetHeight - window.innerHeight);
      const p = clamp(-sec.getBoundingClientRect().top / total, 0, 1);
      if (p === lastP) return; lastP = p;
      const pos = p * (N - 1);
      paneRefs.current.forEach((el, i) => {
        if (!el) return;
        const off = i - pos;
        const a = clamp(1 - Math.abs(off) * 1.6, 0, 1);
        el.style.opacity = String(a);
        el.style.transform = `translateY(${off * 12}vh) scale(${0.94 + 0.06 * a})`;
        el.style.filter = `blur(${Math.min(7, Math.abs(off) * 8)}px)`;
        el.style.pointerEvents = Math.abs(off) < 0.5 ? 'auto' : 'none';
        el.style.zIndex = Math.abs(off) < 0.5 ? 3 : 1;
      });
      const idx = clamp(Math.round(pos), 0, N - 1);
      if (counterRef.current) counterRef.current.textContent = String(idx + 1).padStart(2, '0');
      railRef.current.forEach((r, i) => {
        if (!r) return;
        r.style.height = i === idx ? '30px' : '14px';
        r.style.background = i === idx ? 'var(--accent)' : 'var(--hairline-strong)';
      });
    };
    const loop = () => { apply(); if (alive) raf = requestAnimationFrame(loop); };
    const onEvt = () => apply();
    raf = requestAnimationFrame(loop);
    ['scroll', 'wheel', 'touchmove', 'resize'].forEach((e) => window.addEventListener(e, onEvt, { passive: true }));
    const detachSnap = attachStepSnap(secRef, N);
    apply();
    return () => {
      alive = false; cancelAnimationFrame(raf); detachSnap();
      ['scroll', 'wheel', 'touchmove', 'resize'].forEach((e) => window.removeEventListener(e, onEvt));
    };
  }, [N]);

  const goTo = (i) => {
    const sec = secRef.current; if (!sec) return;
    const total = sec.offsetHeight - window.innerHeight;
    window.scrollTo({ top: sec.offsetTop + (i / (N - 1)) * total, behavior: 'smooth' });
  };

  // ---- reduced-motion: plain stacked list, no choreography ----
  if (reduced) {
    return (
      <section id="projects" data-screen-label="Projects / Projekti" style={{ padding: `${SEC_Y} 0`, background: 'var(--bg-sunken)' }}>
        <div style={{ maxWidth: 1200, margin: '0 auto', padding: `0 ${PAD_X}` }}>
          <SectionHead t={t} kicker={t.projects.kicker} title={t.projects.title} lede={t.projects.lede} />
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 'clamp(56px,10vw,96px)', marginTop: 'clamp(32px,5vw,48px)' }}>
          {slate.map((s, i) => <ProjectPane key={i} s={s} idx={i} total={N} onPlay={() => onPlay(s)} />)}
        </div>
      </section>);
  }

  // ---- desktop: pinned scroll-scrub stage ----
  return (
    <section id="projects" data-screen-label="Projects / Projekti" ref={secRef} style={{ position: 'relative', height: `${N * 100}vh`, background: 'var(--bg-sunken)' }}>
      <div style={{ position: 'sticky', top: 0, height: '100svh', overflow: 'hidden' }}>
        {/* fixed section header */}
        <div style={{ position: 'absolute', top: 'clamp(92px,13vh,128px)', left: PAD_X, right: PAD_X, display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', zIndex: 5 }}>
          <div>
            <Eyebrow>{t.projects.kicker}</Eyebrow>
            <h2 className="es-display" style={{ fontSize: 'clamp(26px,3.6vw,48px)', margin: '12px 0 0' }}>{t.projects.title}</h2>
          </div>
          <div className="es-caption" style={{ color: 'var(--fg3)', fontSize: 13, paddingTop: 4 }}>
            <span ref={counterRef} style={{ color: 'var(--accent-ink)' }}>01</span> / {String(N).padStart(2, '0')}
          </div>
        </div>

        {/* stacked panes */}
        {slate.map((s, i) =>
        <div key={i} ref={(el) => paneRefs.current[i] = el} style={{
          position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center',
          paddingTop: 'clamp(96px, 13vh, 140px)', opacity: i === 0 ? 1 : 0, willChange: 'opacity, transform, filter',
        }}>
          <ProjectPane s={s} idx={i} total={N} onPlay={() => onPlay(s)} />
        </div>)}

        {/* progress rail */}
        <div style={{ position: 'absolute', right: 'clamp(16px,2.4vw,34px)', top: '50%', transform: 'translateY(-50%)', display: 'flex', flexDirection: 'column', gap: 10, zIndex: 5 }}>
          {slate.map((s, i) =>
          <button key={i} ref={(el) => railRef.current[i] = el} onClick={() => goTo(i)} aria-label={`${i + 1}. ${s.title}`} style={{
            width: 3, height: i === 0 ? 30 : 14, padding: 0, border: 0, borderRadius: 999, cursor: 'pointer',
            background: i === 0 ? 'var(--accent)' : 'var(--hairline-strong)', transition: 'height var(--dur-base) var(--ease-out), background var(--dur-base) var(--ease-out)',
          }} />)}
        </div>
      </div>
    </section>);
}

function Projects({ t }) {
  const [video, setVideo] = uS(null);
  const onPlay = (s) => {
    if (s.youtube || s.video) setVideo(s);
    else if (s.link) window.open(s.link, '_blank', 'noopener');
  };
  return (
    <>
      <ProjectsShowcase t={t} onPlay={onPlay} />
      <section style={{ padding: `clamp(56px,8vw,88px) ${PAD_X} ${SEC_Y}`, background: 'var(--bg-sunken)' }}>
        <div style={{ maxWidth: 1200, margin: '0 auto' }}>
          <Reveal y={18}><Eyebrow style={{ marginBottom: 24 }}>{t.projects.tableTitle || t.projects.kicker}</Eyebrow></Reveal>
          <ProductionsTable t={t} />
        </div>
      </section>
      {video && <VideoModal project={video} onClose={() => setVideo(null)} />}
    </>);
}

function ProductionsTable({ t }) {
  const accentStatuses = [t.projects.onair];
  return (
    <div>
      <div className="prod-grid" style={{ padding: '0 4px 14px', borderBottom: '1px solid var(--hairline-strong)' }}>
        {t.projects.tableHead.map((h) => <span key={h} className="es-caption" style={{ color: 'var(--fg3)' }}>{h}</span>)}
      </div>
      {t.projects.rows.map((r, i) =>
      <Reveal key={i} delay={Math.min(i, 6) * 60} y={16} dur={620}>
        <div className="prod-grid ns-row" style={{ padding: '18px 4px', borderBottom: '1px solid var(--hairline)', alignItems: 'center', cursor: 'pointer', transition: 'background var(--dur-fast) var(--ease-out)' }}>
          <span style={{ fontFamily: 'var(--font-display)', fontWeight: 700, textTransform: 'uppercase', fontSize: 18, letterSpacing: '-0.01em', color: 'var(--fg1)' }}>{r[0]}</span>
          <span className="es-small" style={{ color: 'var(--fg2)' }}>{r[1]}</span>
          <span style={{ fontFamily: 'var(--font-mono)', fontSize: 13, color: 'var(--fg3)' }}>{r[2]}</span>
          <span style={{ fontFamily: 'var(--font-mono)', fontSize: 11, letterSpacing: '0.1em', textTransform: 'uppercase', color: accentStatuses.includes(r[3]) ? 'var(--accent-ink)' : 'var(--fg3)' }}>{r[3]}</span>
        </div>
        </Reveal>
      )}
    </div>);

}

/* ============================ QUOTE ============================ */
function QuoteBand({ t }) {
  return (
    <section style={{ padding: `clamp(72px,11vw,120px) ${PAD_X}`, textAlign: 'center', background: 'var(--bg)' }}>
      <div style={{ maxWidth: 960, margin: '0 auto', display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
        <Reveal y={16} style={{ display: 'flex' }}><Mark size={40} /></Reveal>
        <Reveal as="blockquote" className="es-quote" delay={120} blur style={{ fontSize: 'clamp(26px,4.5vw,44px)', lineHeight: 1.25, margin: '26px 0 0', letterSpacing: '-0.01em' }}>“{t.quote.text}”</Reveal>
        <Reveal className="es-caption" delay={260} style={{ color: 'var(--fg3)', marginTop: 24 }}>— {t.quote.attr}</Reveal>
      </div>
    </section>);

}

/* ============================ CONTACT ============================ */
function Contact({ t, lang }) {
  return (
    <section id="contact" data-screen-label="Contact / Kontakt" style={{ padding: `${SEC_Y} ${PAD_X}`, background: 'var(--bg-sunken)' }}>
      <div style={{ maxWidth: 1200, margin: '0 auto' }}>
        <div className="contact-grid" style={{ display: 'grid', gap: 'clamp(36px,5vw,72px)', alignItems: 'start' }}>
          <div>
            <Reveal y={18}><Eyebrow style={{ marginBottom: 14 }}>{t.contact.kicker}</Eyebrow></Reveal>
            <Reveal as="h2" className="es-display" delay={80} blur style={{ fontSize: 'clamp(40px,7vw,84px)', margin: '0 0 22px' }}>{t.contact.title}</Reveal>
            <Reveal as="p" className="es-lede" delay={170} style={{ fontSize: 'clamp(17px,2.2vw,22px)', margin: '0 0 40px', maxWidth: 460 }}>{t.contact.lede}</Reveal>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>
              {t.contact.details.map(([icon, label, val], i) =>
              <Reveal key={i} delay={240 + i * 80} y={18} style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
                  <span style={{ width: 44, height: 44, borderRadius: 'var(--r-sm)', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', background: 'var(--bg-raised)', border: '1px solid var(--hairline)', color: 'var(--accent-ink)', flex: '0 0 auto' }}><Icon name={icon} size={20} /></span>
                  <div>
                    <div className="es-caption" style={{ color: 'var(--fg3)', marginBottom: 2 }}>{label}</div>
                    <div style={{ fontFamily: 'var(--font-sans)', fontWeight: 600, fontSize: 16, color: 'var(--fg1)' }}>{val}</div>
                  </div>
                </Reveal>
              )}
            </div>
            <div style={{ display: 'flex', gap: 12, marginTop: 32 }}>
              {t.contact.socials.map((s) =>
              <a key={s} href="#" onClick={(e) => e.preventDefault()} className="social-btn" style={{ width: 44, height: 44, borderRadius: 'var(--r-sm)', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', border: '1px solid var(--hairline)', color: 'var(--fg2)', transition: 'all var(--dur-base) var(--ease-out)' }}><Icon name={s} size={20} /></a>
              )}
            </div>
          </div>
          <Reveal delay={120} y={34} style={{ height: '100%' }}><ContactForm t={t} /></Reveal>
        </div>
      </div>
    </section>);

}

function ContactForm({ t }) {
  const [state, setState] = uS('idle'); // idle | sending | sent
  const [form, setForm] = uS({ name: '', email: '', org: '', type: t.contact.form.typeOptions[0], message: '' });
  const [touched, setTouched] = uS(false);
  const valid = form.name.trim() && /.+@.+\..+/.test(form.email) && form.message.trim();

  const submit = (e) => {
    e.preventDefault();
    setTouched(true);
    if (!valid || state !== 'idle') return;
    setState('sending');
    setTimeout(() => setState('sent'), 1100);
  };

  const field = (key, type = 'text') =>
  <div>
      <label className="es-caption" style={{ display: 'block', color: 'var(--fg3)', marginBottom: 8 }}>{t.contact.form[key]}</label>
      <input
      type={type} value={form[key]} onChange={(e) => setForm({ ...form, [key]: e.target.value })}
      className="es-input"
      style={{ width: '100%', padding: '13px 16px', borderRadius: 'var(--r-sm)', border: `1px solid ${touched && (key === 'name' && !form.name.trim() || key === 'email' && !/.+@.+\..+/.test(form.email)) ? 'var(--critical)' : 'var(--hairline-strong)'}`, background: 'var(--bg-raised)', color: 'var(--fg1)', fontFamily: 'var(--font-sans)', fontSize: 15, outline: 'none', transition: 'border-color var(--dur-fast)' }} />
    
    </div>;


  if (state === 'sent') {
    return (
      <div style={{ background: 'var(--bg-raised)', border: '1px solid var(--accent)', borderRadius: 'var(--r-md)', padding: 'clamp(32px,4vw,48px)', display: 'flex', flexDirection: 'column', alignItems: 'flex-start', minHeight: 360, justifyContent: 'center' }}>
        <span style={{ width: 56, height: 56, borderRadius: '50%', background: 'var(--accent)', color: 'var(--accent-contrast)', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', marginBottom: 22 }}><Icon name="check" size={28} stroke={2.5} /></span>
        <div style={{ fontFamily: 'var(--font-display)', fontWeight: 800, textTransform: 'uppercase', fontSize: 24, color: 'var(--fg1)', marginBottom: 12 }}>{t.cta.sent}</div>
        <p className="es-body" style={{ color: 'var(--fg2)', margin: 0, maxWidth: 380 }}>{t.contact.success}</p>
      </div>);

  }

  return (
    <form onSubmit={submit} style={{ background: 'var(--bg-raised)', border: '1px solid var(--hairline)', borderRadius: 'var(--r-md)', padding: 'clamp(24px,3.5vw,40px)', display: 'flex', flexDirection: 'column', gap: 18, boxShadow: 'var(--shadow-sm)' }}>
      {field('name')}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 200px), 1fr))', gap: 18 }}>
        {field('email', 'email')}
        {field('org')}
      </div>
      <div>
        <label className="es-caption" style={{ display: 'block', color: 'var(--fg3)', marginBottom: 8 }}>{t.contact.form.type}</label>
        <select value={form.type} onChange={(e) => setForm({ ...form, type: e.target.value })} className="es-input" style={{ width: '100%', padding: '13px 16px', borderRadius: 'var(--r-sm)', border: '1px solid var(--hairline-strong)', background: 'var(--bg-raised)', color: 'var(--fg1)', fontFamily: 'var(--font-sans)', fontSize: 15, outline: 'none', appearance: 'none', cursor: 'pointer' }}>
          {t.contact.form.typeOptions.map((o) => <option key={o} value={o}>{o}</option>)}
        </select>
      </div>
      <div>
        <label className="es-caption" style={{ display: 'block', color: 'var(--fg3)', marginBottom: 8 }}>{t.contact.form.message}</label>
        <textarea value={form.message} onChange={(e) => setForm({ ...form, message: e.target.value })} rows={4} className="es-input" style={{ width: '100%', padding: '13px 16px', borderRadius: 'var(--r-sm)', border: `1px solid ${touched && !form.message.trim() ? 'var(--critical)' : 'var(--hairline-strong)'}`, background: 'var(--bg-raised)', color: 'var(--fg1)', fontFamily: 'var(--font-sans)', fontSize: 15, outline: 'none', resize: 'vertical' }} />
      </div>
      <Button style={{ width: '100%', padding: '16px', marginTop: 4, opacity: state === 'sending' ? 0.7 : 1 }} iconRight={state === 'sending' ? null : 'arrow-right'}>
        {state === 'sending' ? t.cta.sending : t.cta.send}
      </Button>
    </form>);

}

/* ============================ CTA BAND ============================ */
function CTABand({ t }) {
  return (
    <section style={{ padding: `0 ${PAD_X} clamp(72px,11vw,120px)`, background: 'var(--bg)' }}>
      <Reveal y={36} dur={900} style={{ maxWidth: 1200, margin: '0 auto', background: 'linear-gradient(135deg, var(--gold), var(--gold-600))', borderRadius: 'var(--r-xl)', padding: 'clamp(40px,6vw,72px) clamp(32px,5vw,64px)', display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 40, flexWrap: 'wrap', position: 'relative', overflow: 'hidden' }}>
        <img src="assets/eurostar-mark.png" alt="" style={{ position: 'absolute', right: -40, bottom: -60, width: 340, opacity: 0.1, pointerEvents: 'none' }} />
        <div style={{ position: 'relative' }}>
          <h2 style={{ fontFamily: 'var(--font-display)', fontWeight: 900, textTransform: 'uppercase', fontSize: 'clamp(34px,5.5vw,56px)', letterSpacing: '-0.03em', margin: '0 0 14px', color: 'var(--charcoal)', lineHeight: 0.95 }}>{t.ctaBand.title1}<br />{t.ctaBand.title2}</h2>
          <p style={{ fontFamily: 'var(--font-sans)', fontSize: 'clamp(15px,1.8vw,17px)', color: 'rgba(42,44,49,0.82)', margin: 0, maxWidth: 460, lineHeight: 1.5 }}>{t.ctaBand.body}</p>
        </div>
        <button className="ns-cta-dark" onClick={() => document.getElementById('contact')?.scrollIntoView({ behavior: 'smooth' })} style={{ position: 'relative', fontFamily: 'var(--font-display)', fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.12em', fontSize: 14, padding: '18px 34px', borderRadius: 'var(--r-md)', background: 'var(--charcoal)', color: 'var(--off-white)', border: 'none', cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: 10, transition: 'all var(--dur-base) var(--ease-out)' }}>
          {t.cta.access} <Icon name="arrow-right" size={17} />
        </button>
      </Reveal>
    </section>);

}

/* ============================ FOOTER ============================ */
function SiteFooter({ t, theme }) {
  return (
    <footer style={{ padding: `clamp(56px,8vw,72px) ${PAD_X} clamp(40px,6vw,56px)`, borderTop: '1px solid var(--hairline)', background: 'var(--bg)' }}>
      <div style={{ maxWidth: 1200, margin: '0 auto' }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', gap: 48, flexWrap: 'wrap', marginBottom: 48 }}>
          <div style={{ maxWidth: 320 }}>
            <Logo height={40} theme={theme} />
            <p className="es-small" style={{ color: 'var(--fg3)', lineHeight: 1.6, margin: '18px 0 0' }}>{t.footer.tagline}</p>
          </div>
          <div style={{ display: 'flex', gap: 'clamp(32px,5vw,64px)', flexWrap: 'wrap' }}>
            {t.footer.cols.map(([h, items]) =>
            <div key={h}>
                <div className="es-caption" style={{ color: 'var(--fg3)', marginBottom: 16 }}>{h}</div>
                <div style={{ display: 'flex', flexDirection: 'column', gap: 11 }}>
                  {items.map((it) => <a key={it} href="#" onClick={(e) => e.preventDefault()} className="ns-link" style={{ fontFamily: 'var(--font-sans)', fontSize: 14, color: 'var(--fg2)', textDecoration: 'none', transition: 'color var(--dur-fast)' }}>{it}</a>)}
                </div>
              </div>
            )}
          </div>
        </div>
        <div style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--fg-muted)', letterSpacing: '0.08em', borderTop: '1px solid var(--hairline)', paddingTop: 28 }}>{t.footer.rights}</div>
      </div>
    </footer>);

}

/* ============================ shared ============================ */
function SectionHead({ kicker, title, lede }) {
  return (
    <div style={{ marginBottom: 'clamp(32px,4.5vw,52px)', maxWidth: 720 }}>
      <Reveal y={20}><Eyebrow style={{ marginBottom: 14 }}>{kicker}</Eyebrow></Reveal>
      <Reveal as="h2" className="es-display" delay={90} blur style={{ fontSize: 'clamp(40px,7vw,84px)', margin: '0 0 18px' }}>{title}</Reveal>
      {lede && <Reveal as="p" className="es-lede" delay={180} style={{ fontSize: 'clamp(17px,2.2vw,24px)', margin: 0 }}>{lede}</Reveal>}
    </div>);

}

Object.assign(window, { Hero, About, StatsBand, Services, Projects, QuoteBand, Contact, CTABand, SiteFooter });