/* Operis — Animated explainer
   Scenes built on top of animations.jsx primitives.
   Story arc:
     S1  0–5    Construction context
     S2  5–13   Chaos (spreadsheets, WhatsApp, lost deliveries)
     S3  13–19  One platform
     S4  19–33  The flow: Requisition → PO → GRN → Invoice
     S5  33–37  Time saved (days → minutes)
     S6  37–40  CTA
*/

/* Bilingual EN/EL. Lang comes from window.OPERIS_LANG, set by:
   1) ?lang=gr query param on /video.html, OR
   2) localStorage['operis-lang'], OR
   3) postMessage({type:'operis-lang', lang:'gr'}) from the parent (i18n.js). */
(function initLang() {
  if (typeof window === 'undefined') return;
  if (window.OPERIS_LANG) return;
  try {
    const p = new URLSearchParams(location.search);
    const urlLang = p.get('lang');
    if (urlLang === 'gr' || urlLang === 'en') { window.OPERIS_LANG = urlLang; return; }
  } catch {}
  try {
    const stored = localStorage.getItem('operis-lang');
    if (stored === 'gr' || stored === 'en') { window.OPERIS_LANG = stored; return; }
  } catch {}
  window.OPERIS_LANG = 'en';
})();
function tr(en, gr) {
  return (typeof window !== 'undefined' && window.OPERIS_LANG === 'gr') ? gr : en;
}

const C = {
  ink:    '#09111f',
  ink2:   '#0c1426',
  navy:   '#0f1f45',
  navy2:  '#142a5c',
  chalk:  '#e8edf5',
  muted:  '#8a96ad',
  line:   'rgba(232,237,245,0.10)',
  line2:  'rgba(232,237,245,0.18)',
  accent: '#2f6de1',
  accent2:'#5b8df0',
  gold:   '#c9a227',
  hardhat:'#f0b400',
  ok:     '#34d399',
  red:    '#ef4444',
};

const mono = 'JetBrains Mono, ui-monospace, monospace';
const sans = 'Inter, system-ui, sans-serif';

/* ───────────────────────── tiny helpers ───────────────────────── */

function ScreenLabel() {
  const time = useTime();
  const sec = Math.floor(time);
  React.useEffect(() => {
    const root = document.querySelector('[data-video-root]');
    if (root) root.setAttribute('data-screen-label', `t=${String(sec).padStart(2,'0')}s`);
  }, [sec]);
  return null;
}

/* a CSS-only grid background that "draws in" */
function GridBackdrop({ start = 0, color = 'rgba(91,141,240,0.10)' }) {
  const t = useTime();
  const p = clamp((t - start) / 1.2, 0, 1);
  return (
    <div style={{
      position: 'absolute', inset: 0,
      backgroundImage: `linear-gradient(${color} 1px, transparent 1px), linear-gradient(90deg, ${color} 1px, transparent 1px)`,
      backgroundSize: '64px 64px',
      opacity: p,
      maskImage: 'radial-gradient(ellipse 80% 70% at 50% 50%, #000 40%, transparent 100%)',
    }}/>
  );
}

/* fade a panel in/out by absolute time window with extra control */
function Fade({ start, end, fadeIn = 0.4, fadeOut = 0.4, children, style }) {
  const t = useTime();
  let opacity = 0;
  if (t >= start && t <= end) {
    if (t < start + fadeIn) opacity = (t - start) / fadeIn;
    else if (t > end - fadeOut) opacity = clamp((end - t) / fadeOut, 0, 1);
    else opacity = 1;
  }
  if (opacity <= 0.001) return null;
  return <div style={{ opacity, ...style }}>{children}</div>;
}

/* ───────────────────────── SCENE 1 — Construction ─────────────────────────
   Three connected zones — Office · Site · Deliveries — with a data loop
   so the link between them is immediately obvious.                          */

const ZONE_OFFICE   = { cx: 440,  name: 'OFFICE',     sub: 'Procurement & approvals' };
const ZONE_SITE     = { cx: 960,  name: 'SITE 04',    sub: 'Limassol · foundations & frame' };
const ZONE_DELIVERY = { cx: 1480, name: 'DELIVERIES', sub: 'Supplier · GRN at the gate' };
const BUS_Y = 920;

function Scene1() {
  return (
    <Sprite start={0} end={5.2}>
      {({ localTime }) => (
        <div style={{ position:'absolute', inset:0 }}>
          <GridBackdrop start={0} color="rgba(91,141,240,0.10)"/>
          <Scene1Title    t={localTime}/>
          <OfficeZone     t={localTime}/>
          <SiteZone       t={localTime}/>
          <DeliveryZone   t={localTime}/>
          <Scene1FlowBus  t={localTime}/>
        </div>
      )}
    </Sprite>
  );
}

function Scene1Title({ t }) {
  const eyOp  = clamp((t-0.3)/0.4, 0, 1);
  const tiOp  = clamp((t-0.55)/0.6, 0, 1);
  const tiTy  = (1 - clamp((t-0.55)/0.7, 0, 1)) * 14;
  const subOp = clamp((t-1.1)/0.5, 0, 1);
  return (
    <div style={{ position:'absolute', top: 90, left: 0, right: 0, textAlign:'center' }}>
      <div style={{
        fontFamily: mono, fontSize: 13, letterSpacing:'0.24em',
        color: C.accent2, opacity: eyOp, marginBottom: 14,
      }}>
        OPERIS · /build · CONSTRUCTION OPERATIONS
      </div>
      <div style={{
        fontFamily: sans, fontSize: 72, fontWeight: 600,
        color: C.chalk, letterSpacing:'-0.025em', lineHeight: 1.02,
        opacity: tiOp, transform: `translateY(${tiTy}px)`,
      }}>
        {tr('Office. Site. Deliveries.', 'Γραφείο. Εργοτάξιο. Παραδόσεις.')}<br/>
        <span style={{ color: C.muted }}>{tr('One operating layer.', 'Ένα λειτουργικό επίπεδο.')}</span>
      </div>
      <div style={{
        fontFamily: sans, fontSize: 20, color: C.muted, marginTop: 16,
        opacity: subOp,
      }}>
        {tr(
          'Procurement from the office. Goods received on site. Costs reconciled in real time.',
          'Προμήθειες από το γραφείο. Παραλαβή στο εργοτάξιο. Συμφωνία κόστους σε πραγματικό χρόνο.'
        )}
      </div>
    </div>
  );
}

/* — OFFICE zone: a monitor on a desk showing an approved PO — */
function OfficeZone({ t }) {
  const appear = clamp((t-0.7)/0.5, 0, 1);
  return (
    <div style={{
      position:'absolute', left: ZONE_OFFICE.cx - 220, top: 470,
      width: 440, opacity: appear,
      transform: `translateY(${(1-appear)*14}px)`,
    }}>
      <div style={{
        width: 420, height: 260, margin: '0 auto',
        background: 'linear-gradient(180deg,#0c1426,#0a1322)',
        border: `2px solid ${C.line2}`, borderRadius: 12, padding: 18,
        boxShadow: '0 24px 60px rgba(0,0,0,0.5)',
        position:'relative', fontFamily: sans,
      }}>
        <div style={{ display:'flex', alignItems:'center', gap:6, marginBottom: 14 }}>
          <span style={{ width:10, height:10, borderRadius:99, background:'#ef4444', opacity:0.7 }}/>
          <span style={{ width:10, height:10, borderRadius:99, background:'#f59e0b', opacity:0.7 }}/>
          <span style={{ width:10, height:10, borderRadius:99, background:'#10b981', opacity:0.7 }}/>
          <div style={{ fontFamily: mono, fontSize: 11, color: C.muted, marginLeft: 12 }}>
            operis · purchase order
          </div>
        </div>
        <div style={{ fontFamily: mono, fontSize: 12, color: C.accent2, marginBottom: 4 }}>
          PO-2024-1138 · DRAFT → APPROVED
        </div>
        <div style={{
          fontFamily: sans, fontSize: 22, color: C.chalk, fontWeight: 600,
          marginBottom: 14, letterSpacing:'-0.01em',
        }}>
          Concrete C30 · 24 m³
        </div>
        <div style={{
          display:'grid', gridTemplateColumns:'auto 1fr', gap:'7px 14px',
          fontFamily: mono, fontSize: 12, color: C.muted,
        }}>
          <div>activity</div><div style={{ color: C.chalk }}>CS030.04.01</div>
          <div>supplier</div><div style={{ color: C.chalk }}>NHD Steel & Concrete</div>
          <div>site</div><div style={{ color: C.chalk }}>04 · Limassol</div>
        </div>
        <div style={{
          position:'absolute', right: 14, bottom: 12,
          display:'inline-flex', alignItems:'center', gap:6, padding:'4px 10px',
          background:'rgba(52,211,153,0.10)',
          border:'1px solid rgba(52,211,153,0.35)',
          borderRadius: 6, fontFamily: mono, fontSize: 11, color: C.ok,
        }}>
          ✓ approved
        </div>
      </div>
      {/* desk + stand */}
      <div style={{ width: 220, height: 6, background: C.line2, margin: '14px auto 0', borderRadius: 3 }}/>
      <div style={{ width: 340, height: 8, background: C.line,  margin: '0 auto',     borderRadius: 4 }}/>
      <ZoneCaption {...ZONE_OFFICE} t={t}/>
    </div>
  );
}

/* — SITE zone: static crane + rising building + scaffold + tiny workers — */
function SiteZone({ t }) {
  const appear = clamp((t-0.5)/0.5, 0, 1);
  // gentle hook bob (cable goes up/down a little)
  const hookY = 130 + 8 * Math.sin(t * 1.2);
  return (
    <div style={{
      position:'absolute', left: ZONE_SITE.cx - 240, top: 350,
      width: 480, opacity: appear,
    }}>
      <svg width="480" height="420" viewBox="0 0 480 420" style={{ overflow:'visible' }}>
        {/* — STATIC CRANE on right — */}
        <g transform="translate(360, 24)">
          {/* base */}
          <rect x="-10" y="356" width="36" height="6" fill={C.gold}/>
          {/* mast */}
          <rect x="0" y="0" width="16" height="360" fill={C.gold}/>
          {Array.from({length: 18}).map((_,i) => (
            <g key={i} stroke="rgba(0,0,0,0.35)" strokeWidth="1">
              <line x1="2"  y1={i*20} x2="14" y2={i*20+10}/>
              <line x1="14" y1={i*20} x2="2"  y2={i*20+10}/>
            </g>
          ))}
          {/* turntable + cab */}
          <rect x="-2" y="-6"  width="20" height="10" fill={C.gold}/>
          <rect x="-2" y="-24" width="20" height="14" fill={C.ink} stroke={C.gold} strokeWidth="1"/>
          {/* jib pointing LEFT toward the building, fixed angle */}
          <g transform="translate(8, -2)">
            <rect x="-300" y="-3" width="320" height="6" fill={C.gold}/>
            {/* apex tie */}
            <line x1="-260" y1="-2" x2="0" y2="-30" stroke={C.gold} strokeWidth="2"/>
            <line x1="40"  y1="-2" x2="0" y2="-30" stroke={C.gold} strokeWidth="2"/>
            {/* tower-top */}
            <rect x="-3" y="-34" width="8" height="10" fill={C.gold}/>
            {Array.from({length: 12}).map((_,i) => (
              <line key={i}
                    x1={-296 + i*26} y1="-10"
                    x2={-296 + i*26 + 13} y2="10"
                    stroke="rgba(0,0,0,0.35)" strokeWidth="1"/>
            ))}
            {/* counter-jib */}
            <rect x="20" y="-2" width="38" height="4" fill={C.gold}/>
            <rect x="48" y="-12" width="14" height="10" fill={C.ink} stroke={C.gold} strokeWidth="0.5"/>
            {/* trolley + cable + hook (only the hook bobs) */}
            <line x1="-200" y1="2" x2="-200" y2={hookY}
                  stroke={C.chalk} strokeWidth="1" opacity="0.7"/>
            <rect x="-208" y={hookY} width="16" height="10" fill={C.gold}/>
            <rect x="-220" y={hookY + 12} width="40" height="3" fill={C.muted}/>
          </g>
        </g>

        {/* — Foundation — */}
        <rect x="40" y="362" width="300" height="6" fill={C.gold}
              opacity={clamp((t-0.7)/0.3, 0, 1)}/>

        {/* — Building floors (5 levels) rising — */}
        {Array.from({length: 5}).map((_, i) => {
          const fAppear = clamp((t - 1.0 - i*0.2) / 0.4, 0, 1);
          const floorH = 56;
          const floorY = 362 - (i+1)*floorH;
          return (
            <g key={i} opacity={fAppear} transform={`translate(0, ${(1-fAppear)*12})`}>
              <rect x="60" y={floorY} width="260" height={floorH-4}
                    fill={i === 4 ? 'rgba(47,109,225,0.18)' : 'rgba(91,141,240,0.06)'}
                    stroke={C.line2} strokeWidth="1"/>
              {Array.from({length: 5}).map((_,c) => (
                <rect key={c} x={70 + c*52} y={floorY + 8} width="40" height={floorH - 20}
                      fill="rgba(91,141,240,0.18)"
                      stroke="rgba(91,141,240,0.3)" strokeWidth="0.5"/>
              ))}
            </g>
          );
        })}

        {/* — Scaffold on left side of building — */}
        <g opacity={clamp((t-1.5)/0.4, 0, 1)} stroke={C.muted} strokeWidth="1" fill="none">
          <line x1="50" y1="362" x2="50" y2="120"/>
          <line x1="54" y1="362" x2="54" y2="120"/>
          {Array.from({length: 5}).map((_,i) => (
            <line key={i} x1="46" y1={362 - i*52} x2="58" y2={362 - i*52}/>
          ))}
        </g>

        {/* — Tiny hard-hat workers on the slab — */}
        <g opacity={clamp((t-1.8)/0.4, 0, 1)}>
          <circle cx="120" cy="356" r="4" fill={C.hardhat}/>
          <line x1="120" y1="360" x2="120" y2="376" stroke={C.chalk} strokeWidth="2"/>
          <line x1="120" y1="366" x2="114" y2="372" stroke={C.chalk} strokeWidth="1.5"/>
          <line x1="120" y1="366" x2="126" y2="372" stroke={C.chalk} strokeWidth="1.5"/>
          <circle cx="200" cy="356" r="4" fill={C.hardhat}/>
          <line x1="200" y1="360" x2="200" y2="376" stroke={C.chalk} strokeWidth="2"/>
          <line x1="200" y1="366" x2="194" y2="372" stroke={C.chalk} strokeWidth="1.5"/>
          <line x1="200" y1="366" x2="206" y2="372" stroke={C.chalk} strokeWidth="1.5"/>
        </g>
      </svg>
      <ZoneCaption {...ZONE_SITE} t={t}/>
    </div>
  );
}

/* — DELIVERY zone: a truck parked at the site gate — */
function DeliveryZone({ t }) {
  const appear = clamp((t-1.0)/0.5, 0, 1);
  const truckShift = animate({ from: 60, to: 0, start: 1.0, end: 3.5, ease: Easing.easeOutCubic })(t);
  return (
    <div style={{
      position:'absolute', left: ZONE_DELIVERY.cx - 220, top: 520,
      width: 440, opacity: appear,
    }}>
      <svg width="440" height="220" viewBox="0 0 440 220" style={{ overflow:'visible' }}>
        {/* gate posts */}
        <g opacity={clamp((t-0.8)/0.4, 0, 1)}>
          <rect x="0"  y="40" width="6" height="120" fill={C.gold}/>
          <rect x="0"  y="40" width="400" height="6" fill={C.gold}/>
          <rect x="394" y="40" width="6" height="120" fill={C.gold}/>
          <text x="14" y="34" fill={C.muted} fontFamily="JetBrains Mono"
                fontSize="10" letterSpacing="0.16em">SITE GATE · 04</text>
        </g>

        <g transform={`translate(${truckShift + 14}, 50)`}>
          {/* container */}
          <rect x="0" y="0" width="240" height="110" rx="4"
                fill={C.ink2} stroke={C.gold} strokeWidth="2"/>
          {Array.from({length: 10}).map((_,i) => (
            <line key={i} x1={10 + i*22} y1="6" x2={10 + i*22} y2="104"
                  stroke="rgba(201,162,39,0.22)" strokeWidth="1"/>
          ))}
          {/* logo block */}
          <rect x="14" y="20" width="36" height="36" fill={C.accent}/>
          <text x="32" y="44" textAnchor="middle" fill="#fff"
                fontFamily="Inter" fontSize="20" fontWeight="700">N</text>
          <text x="58" y="38" fill={C.chalk} fontFamily="Inter" fontSize="13" fontWeight="600">NHD STEEL</text>
          <text x="58" y="54" fill={C.muted} fontFamily="JetBrains Mono" fontSize="10">DELIVERY · 1138</text>
          {/* package icon */}
          <g transform="translate(150, 64)">
            <rect x="0" y="0" width="36" height="36" fill="none" stroke={C.gold} strokeWidth="1.5"/>
            <line x1="18" y1="0" x2="18" y2="36" stroke={C.gold} strokeWidth="1.5"/>
            <line x1="0"  y1="18" x2="36" y2="18" stroke={C.gold} strokeWidth="1.5"/>
          </g>
          {/* cab */}
          <rect x="240" y="30" width="58" height="80" rx="4"
                fill={C.navy2} stroke={C.line2} strokeWidth="2"/>
          <rect x="250" y="40" width="38" height="30" fill={C.accent2} opacity="0.45"/>
          <rect x="246" y="78" width="46" height="6" fill={C.ink2}/>
          {/* wheels */}
          {[40, 100, 190, 270].map((wx,i) => (
            <g key={i}>
              <circle cx={wx} cy="118" r="13" fill={C.ink}/>
              <circle cx={wx} cy="118" r="6"  fill={C.muted}/>
            </g>
          ))}
        </g>
      </svg>
      <ZoneCaption {...ZONE_DELIVERY} t={t}/>
    </div>
  );
}

function ZoneCaption({ name, sub, t }) {
  return (
    <div style={{ marginTop: 24, textAlign:'center', opacity: clamp((t-1.6)/0.4, 0, 1) }}>
      <div style={{
        fontFamily: mono, fontSize: 13, letterSpacing:'0.22em',
        color: C.chalk, marginBottom: 6,
      }}>
        {name}
      </div>
      <div style={{ fontFamily: sans, fontSize: 13, color: C.muted }}>
        {sub}
      </div>
    </div>
  );
}

/* — Flow bus: dashed line tying the three zones together, with traveling
     pulses for PO / TRUCK / GRN. This is the visual proof that the three
     zones are one loop. — */
function Scene1FlowBus({ t }) {
  const y = BUS_Y;
  const cx1 = ZONE_OFFICE.cx;
  const cx2 = ZONE_SITE.cx;
  const cx3 = ZONE_DELIVERY.cx;
  return (
    <svg width="1920" height="1080"
         style={{ position:'absolute', inset:0, pointerEvents:'none' }}>
      {/* horizontal connectors */}
      <line x1={cx1} y1={y} x2={cx2} y2={y}
            stroke={C.line2} strokeWidth="2" strokeDasharray="6 6"
            opacity={clamp((t-1.6)/0.5, 0, 1)}/>
      <line x1={cx2} y1={y} x2={cx3} y2={y}
            stroke={C.line2} strokeWidth="2" strokeDasharray="6 6"
            opacity={clamp((t-1.8)/0.5, 0, 1)}/>
      {/* return arc (site → office) */}
      <path d={`M ${cx2} ${y+22} Q ${(cx1+cx2)/2} ${y+100} ${cx1} ${y+22}`}
            stroke={C.line} strokeWidth="2" strokeDasharray="6 6" fill="none"
            opacity={clamp((t-2.0)/0.5, 0, 1) * 0.7}/>
      {/* nodes at zone centers */}
      {[cx1, cx2, cx3].map((cx, i) => (
        <circle key={i} cx={cx} cy={y} r="7"
                fill={C.ink} stroke={C.accent2} strokeWidth="2"
                opacity={clamp((t-1.2-i*0.2)/0.3, 0, 1)}/>
      ))}
      {/* labels above pulses */}
      <FlowPulse t={t} startT={2.2} dur={1.1} x1={cx1} x2={cx3} y={y} color={C.accent2} label="PO"/>
      <FlowPulse t={t} startT={3.1} dur={0.8} x1={cx3} x2={cx2} y={y} color={C.gold}    label="TRUCK"/>
      <FlowPulse t={t} startT={3.7} dur={1.0} x1={cx2} x2={cx1} y={y} color={C.ok}      label="GRN" arc/>
    </svg>
  );
}

function FlowPulse({ t, startT, dur, x1, x2, y, color, label, arc=false }) {
  if (t < startT || t > startT + dur + 0.4) return null;
  const p = clamp((t - startT) / dur, 0, 1);
  const x = x1 + (x2 - x1) * p;
  const py = arc ? (y + 22 + Math.sin(p * Math.PI) * 78) : y;
  const opacity = p < 0.06 ? p/0.06 : (p > 0.9 ? (1-p)/0.1 : 1);
  return (
    <g style={{ opacity }}>
      <circle cx={x} cy={py} r="9" fill={color}
              style={{ filter: `drop-shadow(0 0 14px ${color})` }}/>
      <text x={x} y={py - 18} fill={color}
            fontFamily="JetBrains Mono" fontSize="12"
            textAnchor="middle" letterSpacing="0.18em" fontWeight="600">
        {label}
      </text>
    </g>
  );
}

/* ───────────────────────── SCENE 2 — Chaos ───────────────────────── */

/* Chaos cluster — confined to the right half of the screen so it doesn't
   collide with the headline on the left. Anchored visually around a frantic
   clock at roughly (1400, 540). */
const CHAOS_ITEMS = [
  /* top band, above the clock */
  {kind:'xls', name:'PO_final.xlsx',                      x: 970,  y: 180, rot:-7},
  {kind:'xls', name:'PO_final_v2.xlsx',                   x: 1230, y: 150, rot: 3},
  {kind:'xls', name:'PO_final_v7_REAL.xlsx',              x: 1470, y: 200, rot:-4},
  {kind:'wa',  name:'site need 40 bags by 10 ok?',        x: 1700, y: 250, rot:-2},
  /* middle band, flanking the clock */
  {kind:'xls', name:'Site4_cost_v12 (3).xlsx',            x: 950,  y: 430, rot:-3},
  {kind:'wa',  name:'Did the cement arrive??',            x: 960,  y: 600, rot:-5},
  {kind:'mail',name:'FW: delivery missing GRN??',         x: 1690, y: 470, rot:-2},
  {kind:'wa',  name:'Boss the invoice doesn\u2019t match', x: 1710, y: 600, rot: 3},
  /* bottom band, below the clock */
  {kind:'xls', name:'Delivery_LP_03.xlsx',                x: 990,  y: 770, rot: 5},
  {kind:'mail',name:'Re: Re: Re: invoice issue',          x: 1230, y: 820, rot: 2},
  {kind:'xls', name:'Sheet1 (2).xlsx',                    x: 1510, y: 870, rot: 6},
  {kind:'mail',name:'Re: cement price update v3',         x: 1680, y: 800, rot: 4},
];

function Scene2() {
  return (
    <Sprite start={5} end={13}>
      {({ localTime, progress }) => {
        // collapse shake near the end
        const collapse = clamp((localTime - 7) / 1.0, 0, 1);
        return (
          <div style={{ position:'absolute', inset:0, background: C.ink }}>
            <GridBackdrop start={5} color="rgba(232,237,245,0.04)"/>

            {/* top eyebrow */}
            <Fade start={5} end={12.5} fadeIn={0.3} fadeOut={0.6}>
              <div style={{
                position:'absolute', top: 80, left: 80,
                fontFamily: mono, fontSize: 14, letterSpacing:'0.22em',
                color: C.red,
              }}>
                {tr('/01 — THE PROBLEM', '/01 — ΤΟ ΠΡΟΒΛΗΜΑ')}
              </div>
            </Fade>

            {/* big headline — confined to the left column so the chaos cluster
               on the right has its own real estate. */}
            <Fade start={5.2} end={12.5} fadeIn={0.5} fadeOut={0.5}>
              <div style={{
                position:'absolute', top: 130, left: 80,
                fontFamily: sans, fontSize: 64, fontWeight: 600,
                color: C.chalk, letterSpacing:'-0.02em', lineHeight: 1.04,
                maxWidth: 800,
              }}>
                {tr('Spreadsheets.', 'Excel.')}<br/>{tr('WhatsApp.', 'WhatsApp.')}<br/>
                <span style={{ color: C.muted }}>{tr('Lost deliveries.', 'Χαμένες παραδόσεις.')}</span>
              </div>
            </Fade>

            {/* supporting paragraph under the headline */}
            <Fade start={5.8} end={12.5} fadeIn={0.5} fadeOut={0.5}>
              <div style={{
                position:'absolute', top: 500, left: 80,
                fontFamily: sans, fontSize: 22, color: C.muted,
                lineHeight: 1.5, maxWidth: 760,
              }}>
                {tr(
                  'For most mid-size contractors, "the system" is a folder of spreadsheets, a few WhatsApp groups, and a PM who never sleeps. It works — until the numbers stop matching.',
                  'Για τους περισσότερους μεσαίους εργολάβους, «το σύστημα» είναι ένας φάκελος Excel, λίγα WhatsApp groups και ένας PM που δεν κοιμάται ποτέ. Λειτουργεί — μέχρι να μην ταιριάζουν πια οι αριθμοί.'
                )}
              </div>
            </Fade>

            {/* the chaos cards */}
            {CHAOS_ITEMS.map((it, i) => {
              const enter = clamp((localTime - 1.0 - i*0.13) / 0.35, 0, 1);
              const shake = collapse * 1;
              const dx = shake * (Math.sin(localTime*8 + i)*8 + (it.x - 1380) * 0.25);
              const dy = shake * (Math.cos(localTime*7 + i)*6 + (it.y - 540)  * 0.25);
              const rot = it.rot + shake * Math.sin(localTime*5+i)*8;
              const opacity = enter * (1 - collapse*0.9);
              return (
                <div key={i} style={{
                  position:'absolute', left: it.x, top: it.y,
                  transform: `translate(${dx}px, ${dy}px) rotate(${rot}deg) scale(${0.92 + 0.08*enter})`,
                  opacity,
                  filter: collapse > 0.6 ? `blur(${(collapse-0.6)*6}px)` : 'none',
                }}>
                  <ChaosCard {...it}/>
                </div>
              );
            })}

            {/* big spinning clock — anchor of the chaos cluster, communicates
               wasted time. */}
            <Fade start={6.2} end={12.5} fadeIn={0.4} fadeOut={0.5}>
              <SpinClock x={1280} y={400} t={localTime}/>
            </Fade>

            {/* stat callout — bottom-left, well under the supporting paragraph */}
            <Fade start={9.5} end={12.5} fadeIn={0.4} fadeOut={0.5}>
              <div style={{
                position:'absolute', left: 80, bottom: 110,
                display:'flex', alignItems:'baseline', gap: 18, maxWidth: 800,
              }}>
                <div style={{
                  fontFamily: sans, fontSize: 96, fontWeight: 700, color: C.red,
                  letterSpacing:'-0.03em', lineHeight: 1,
                }}>€40k</div>
                <div style={{ fontFamily: sans, fontSize: 22, color: C.muted, maxWidth: 540 }}>
                  {tr(
                    "slips through every quarter — invoices that didn't match a delivery.",
                    'χάνονται κάθε τρίμηνο — τιμολόγια που δεν ταίριαξαν με παράδοση.'
                  )}
                </div>
              </div>
            </Fade>
          </div>
        );
      }}
    </Sprite>
  );
}

function ChaosCard({ kind, name }) {
  if (kind === 'xls') {
    return (
      <div style={{
        width: 280, padding: '10px 12px',
        background:'#0f1f2e', border:`1px solid ${C.line2}`,
        borderRadius: 6, display:'flex', alignItems:'center', gap: 10,
        boxShadow:'0 12px 32px rgba(0,0,0,0.5)',
        fontFamily: mono, fontSize: 13, color: C.chalk,
      }}>
        <div style={{
          width: 22, height: 22, borderRadius: 4, background:'#1e7f4d',
          display:'grid', placeItems:'center', color:'#fff', fontWeight:700, fontSize: 11,
          fontFamily: sans,
        }}>X</div>
        <div style={{ whiteSpace:'nowrap', overflow:'hidden', textOverflow:'ellipsis' }}>{name}</div>
      </div>
    );
  }
  if (kind === 'mail') {
    return (
      <div style={{
        width: 320, padding:'10px 12px',
        background:'#181d28', border:`1px solid ${C.line2}`,
        borderRadius: 6, fontFamily: sans, fontSize: 13, color: C.chalk,
        boxShadow:'0 12px 32px rgba(0,0,0,0.5)',
        display:'flex', alignItems:'center', gap: 10,
      }}>
        <svg width="18" height="14" viewBox="0 0 24 18" fill="none" stroke={C.muted} strokeWidth="1.6">
          <rect x="1" y="1" width="22" height="16" rx="1"/>
          <path d="M1 2l11 8 11-8"/>
        </svg>
        <div style={{ whiteSpace:'nowrap', overflow:'hidden', textOverflow:'ellipsis' }}>{name}</div>
      </div>
    );
  }
  if (kind === 'wa') {
    return (
      <div style={{
        maxWidth: 280, padding:'8px 12px',
        background:'#0f4a3a', color:'#dff7eb',
        borderRadius: '14px 14px 14px 2px',
        fontFamily: sans, fontSize: 14,
        boxShadow:'0 12px 32px rgba(0,0,0,0.5)',
      }}>
        {name}
        <div style={{ fontSize: 10, color:'rgba(223,247,235,0.5)', marginTop: 4, textAlign:'right'}}>14:32 ✓✓</div>
      </div>
    );
  }
  return null;
}

function SpinClock({ x, y, t }) {
  const spin = t * 360 * 1.4; // fast
  return (
    <div style={{ position:'absolute', left: x, top: y }}>
      <svg width="280" height="280" viewBox="0 0 100 100">
        <circle cx="50" cy="50" r="44" fill="rgba(239,68,68,0.06)" stroke={C.red} strokeWidth="1.5"/>
        {Array.from({length:12}).map((_,i) => (
          <line key={i} x1="50" y1="10" x2="50" y2="16"
                stroke={C.red} strokeWidth="1.5"
                transform={`rotate(${i*30} 50 50)`}/>
        ))}
        {/* hour hand */}
        <line x1="50" y1="50" x2="50" y2="28" stroke={C.chalk} strokeWidth="2.5"
              transform={`rotate(${spin*0.5} 50 50)`} strokeLinecap="round"/>
        {/* minute hand */}
        <line x1="50" y1="50" x2="50" y2="18" stroke={C.red} strokeWidth="2"
              transform={`rotate(${spin} 50 50)`} strokeLinecap="round"/>
        <circle cx="50" cy="50" r="2.5" fill={C.red}/>
      </svg>
    </div>
  );
}

/* ───────────────────────── SCENE 3 — One platform ───────────────────────── */

/* Three source feeds (Procurement, Labour timesheets, Equipment Plan) all
   flowing into one Cost Control dashboard. Equipment Plan is rendered
   slightly indented and dashed/gold to feel "a bit apart" — it's the
   baseline plan, not actual transactions, but still connected so costs
   land against the plan. */

const DASH_X = 720;
const DASH_Y = 290;
const DASH_W = 1130;
const DASH_H = 720;

const SOURCE_DEFS = {
  procurement: {
    title: 'Procurement & GRN',
    badge: 'P',
    accent: '#2f6de1',
    rows: [
      { k:'PO-1138', v:'Concrete C30 · €84,200' },
      { k:'GRN-441', v:'Rebar Ø12 · 1.2 t received' },
      { k:'PO-1142', v:'Formwork hire · €18,900' },
    ],
    label: 'POS · GRNS',
  },
  labour: {
    title: 'Labour timesheets',
    badge: 'L',
    accent: '#2f6de1',
    rows: [
      { k:'Crew A', v:'8 carpenters · 64h' },
      { k:'Crew B', v:'5 steel-fixers · 40h' },
      { k:'Crew C', v:'3 finishers · 24h' },
    ],
    label: 'CREWS · HOURS',
  },
  equipment: {
    title: 'Equipment plan',
    badge: 'E',
    accent: '#c9a227',
    dashed: true,
    rows: [
      { k:'CRN-01', v:'Tower crane · wk 3-9' },
      { k:'EXC-03', v:'Excavator 24t · wk 1-3' },
      { k:'GEN-12', v:'Genset 200 kVA · 24/7' },
    ],
    label: 'PLAN · BASELINE',
  },
};

function Scene3() {
  return (
    <Sprite start={13} end={19.2}>
      {({ localTime }) => (
        <div style={{ position:'absolute', inset:0, background: C.ink }}>
          <GridBackdrop start={13} color="rgba(91,141,240,0.10)"/>
          <Scene3Title  t={localTime}/>
          <SourceModule x={80}  y={290} kind="procurement" t={localTime} appearT={0.4}/>
          <SourceModule x={80}  y={510} kind="labour"      t={localTime} appearT={0.7}/>
          {/* equipment plan: slightly indented + dashed border to feel separate */}
          <SourceModule x={130} y={770} kind="equipment"   t={localTime} appearT={1.0}/>
          <Scene3Feeders t={localTime}/>
          <CostControlDashboard t={localTime}/>
        </div>
      )}
    </Sprite>
  );
}

function Scene3Title({ t }) {
  const eyOp = clamp((t-0.1)/0.4, 0, 1);
  const tiOp = clamp((t-0.3)/0.5, 0, 1);
  return (
    <div style={{ position:'absolute', top: 90, left: 80, right: 80 }}>
      <div style={{
        fontFamily: mono, fontSize: 13, letterSpacing:'0.22em',
        color: C.accent2, opacity: eyOp, marginBottom: 14,
      }}>
        {tr('/02 — ONE COST LEDGER', '/02 — ΕΝΑ ΚΑΘΟΛΙΚΟ ΚΟΣΤΟΥΣ')}
      </div>
      <div style={{
        fontFamily: sans, fontSize: 38, fontWeight: 600,
        color: C.chalk, letterSpacing:'-0.02em', lineHeight: 1.04,
        opacity: tiOp, maxWidth: 1760, whiteSpace: 'nowrap',
      }}>
        {tr('Procurement, timesheets and the equipment plan —', 'Προμήθειες, ωρομέτρηση και πλάνο εξοπλισμού —')}
        <span style={{ color: C.muted }}>{tr(' feeding one live cost ledger.', ' τροφοδοτούν ένα ζωντανό καθολικό κόστους.')}</span>
      </div>
    </div>
  );
}

function SourceModule({ x, y, kind, t, appearT }) {
  const def = SOURCE_DEFS[kind];
  const appear = clamp((t - appearT)/0.4, 0, 1);
  const goldish = def.accent === '#c9a227';
  return (
    <div style={{
      position:'absolute', left: x, top: y, width: 470, height: 200,
      padding: 18,
      background: goldish
        ? 'linear-gradient(180deg, rgba(201,162,39,0.05), rgba(201,162,39,0.0))'
        : 'linear-gradient(180deg, rgba(255,255,255,0.025), rgba(255,255,255,0.005))',
      border: def.dashed
        ? `1.5px dashed rgba(201,162,39,0.55)`
        : `1px solid ${C.line2}`,
      borderRadius: 12,
      opacity: appear,
      transform: `translateX(${(1-appear)*-18}px)`,
      fontFamily: sans,
      boxShadow: def.dashed ? 'none' : '0 18px 40px -20px rgba(0,0,0,0.5)',
    }}>
      <div style={{
        display:'flex', alignItems:'center', gap: 12, marginBottom: 14,
      }}>
        <div style={{
          width: 30, height: 30, borderRadius: 6,
          background: goldish ? 'rgba(201,162,39,0.18)' : 'rgba(47,109,225,0.18)',
          border: `1px solid ${goldish ? 'rgba(201,162,39,0.5)' : 'rgba(47,109,225,0.5)'}`,
          display:'grid', placeItems:'center',
          color: def.accent,
          fontFamily: mono, fontSize: 14, fontWeight: 700,
        }}>
          {def.badge}
        </div>
        <div style={{
          fontFamily: sans, fontSize: 19, fontWeight: 600,
          color: C.chalk, letterSpacing:'-0.01em',
        }}>
          {def.title}
        </div>
        <div style={{
          marginLeft:'auto', fontFamily: mono, fontSize: 10,
          letterSpacing:'0.18em', color: C.muted,
        }}>
          {def.label}
        </div>
      </div>
      <div style={{
        display:'flex', flexDirection:'column', gap: 8,
        fontFamily: mono, fontSize: 13,
      }}>
        {def.rows.map((r, i) => (
          <div key={i} style={{
            display:'flex', gap: 14, whiteSpace:'nowrap',
            opacity: clamp((t - appearT - 0.3 - i*0.12)/0.3, 0, 1),
          }}>
            <span style={{ color: def.accent, minWidth: 78 }}>{r.k}</span>
            <span style={{ color: C.chalk, opacity: 0.9 }}>{r.v}</span>
          </div>
        ))}
      </div>
    </div>
  );
}

/* Bezier feeders from each source module's right edge into the dashboard's
   left edge, with a traveling pulse per feed. */
function Scene3Feeders({ t }) {
  const feeders = [
    { from:{x:550, y:380}, color:'#5b8df0', startT:1.5 },
    { from:{x:550, y:600}, color:'#5b8df0', startT:1.7 },
    { from:{x:600, y:860}, color:'#c9a227', startT:1.9, dashed:true },
  ];
  const to = { x: DASH_X, y: 580 };
  return (
    <svg width="1920" height="1080" style={{ position:'absolute', inset:0, pointerEvents:'none' }}>
      {feeders.map((f, i) => {
        const drawP = clamp((t - f.startT)/0.55, 0, 1);
        const path  = `M ${f.from.x} ${f.from.y} C ${(f.from.x+to.x)/2 + 40} ${f.from.y}, ${(f.from.x+to.x)/2 - 40} ${to.y}, ${to.x} ${to.y}`;
        return (
          <g key={i}>
            <path d={path}
                  stroke={f.color}
                  strokeWidth="2"
                  strokeDasharray={f.dashed ? '6 6' : `800 800`}
                  strokeDashoffset={f.dashed ? 0 : 800 * (1 - drawP)}
                  fill="none"
                  opacity={f.dashed ? drawP * 0.8 : drawP * 0.6}/>
            {drawP > 0.9 && (
              <polygon
                points={`${to.x-9},${to.y-5} ${to.x},${to.y} ${to.x-9},${to.y+5}`}
                fill={f.color}/>
            )}
            <Scene3Pulse t={t} startT={f.startT + 0.5} dur={0.9}
                         x1={f.from.x} y1={f.from.y}
                         x2={to.x}     y2={to.y}
                         color={f.color}/>
          </g>
        );
      })}
    </svg>
  );
}

function Scene3Pulse({ t, startT, dur, x1, y1, x2, y2, color }) {
  if (t < startT || t > startT + dur + 0.3) return null;
  const p = clamp((t - startT)/dur, 0, 1);
  const x = x1 + (x2 - x1) * p;
  const y = y1 + (y2 - y1) * p;
  const opacity = p < 0.06 ? p/0.06 : (p > 0.9 ? (1-p)/0.1 : 1);
  return (
    <circle cx={x} cy={y} r="7" fill={color} opacity={opacity}
            style={{ filter: `drop-shadow(0 0 12px ${color})` }}/>
  );
}

function CostControlDashboard({ t }) {
  const appear = clamp((t - 1.7)/0.6, 0, 1);
  return (
    <div style={{
      position:'absolute', left: DASH_X, top: DASH_Y, width: DASH_W, height: DASH_H,
      padding: 24,
      background:'linear-gradient(180deg,#0c1426,#0a1322)',
      border:`1px solid ${C.line2}`, borderRadius: 14,
      boxShadow:'0 40px 100px rgba(0,0,0,0.55), 0 0 0 1px rgba(47,109,225,0.10)',
      opacity: appear,
      transform: `translateX(${(1-appear)*22}px)`,
      fontFamily: sans, color: C.chalk, overflow:'hidden',
    }}>
      <div style={{ display:'flex', alignItems:'center', gap: 12, marginBottom: 18 }}>
        <div style={{
          width: 22, height: 22, borderRadius: 5, background: C.accent,
        }}/>
        <div style={{ fontFamily: sans, fontSize: 18, fontWeight: 600, letterSpacing:'-0.01em' }}>
          Cost Control · Site 04
        </div>
        <span style={{
          marginLeft:'auto', display:'inline-flex', alignItems:'center', gap:6,
          fontFamily: mono, fontSize:11, color: C.ok,
        }}>
          <span style={{width:6,height:6,borderRadius:99,background:C.ok}}/> live · updated 12s ago
        </span>
      </div>

      {/* KPIs */}
      <div style={{
        display:'grid', gridTemplateColumns:'repeat(4, 1fr)', gap: 14, marginBottom: 20,
      }}>
        <Kpi t={t} appearT={2.2} label="Budget"     value="€2.40M" sub="contract"           />
        <Kpi t={t} appearT={2.4} label="Committed"  value="€1.82M" sub="POs raised"
             bar={0.76} barColor={C.accent2}/>
        <Kpi t={t} appearT={2.6} label="Spent"      value="€1.51M" sub="GRN + timesheets"
             bar={0.63} barColor={C.ok}/>
        <Kpi t={t} appearT={2.8} label="Plan vs actual" value="−€42k" sub="under plan"
             bar={0.92} barColor={C.gold} pos/>
      </div>

      {/* Rows */}
      <div style={{
        display:'grid',
        gridTemplateColumns:'46px 120px 1.4fr 60px 1fr 1fr 0.85fr',
        gap: 0, fontFamily: mono, fontSize: 11, color: C.muted, padding:'10px 0',
        borderBottom: `1px solid ${C.line}`, letterSpacing:'0.06em',
      }}>
        <div>SRC</div><div>ACTIVITY</div><div>DESCRIPTION</div><div>TYPE</div>
        <div style={{textAlign:'right'}}>PLAN</div>
        <div style={{textAlign:'right'}}>ACTUAL</div>
        <div style={{textAlign:'right'}}>Δ</div>
      </div>
      {[
        { src:'P', code:'CS030.04.01', desc:'Concrete C30 · foundations',     type:'M', plan:'€88,000', act:'€84,200', dv:'−4.3%', ok:true },
        { src:'P', code:'CS030.05.02', desc:'Rebar Ø12 · NHD Steel',           type:'M', plan:'€42,860', act:'€42,860', dv:'0.0%',  ok:true },
        { src:'L', code:'CS030.07.11', desc:'Formwork crew · L8 · w18',        type:'L', plan:'€24,000', act:'€26,100', dv:'+8.8%', ok:false },
        { src:'E', code:'CS030.09.03', desc:'Tower crane · weeks 3-9',         type:'P', plan:'€18,900', act:'€18,900', dv:'0.0%',  ok:true,  planRow:true },
        { src:'L', code:'CS030.11.05', desc:'Steel-fixer crew B · floor 4',    type:'L', plan:'€14,400', act:'€12,800', dv:'−11%',  ok:true },
        { src:'E', code:'CS030.12.02', desc:'Excavator 24t · weeks 1-3',       type:'P', plan:'€9,600',  act:'€9,600',  dv:'0.0%',  ok:true,  planRow:true },
      ].map((r, i) => {
        const rowAppear = clamp((t - 2.6 - i*0.14)/0.35, 0, 1);
        return (
          <div key={i} style={{
            display:'grid',
            gridTemplateColumns:'46px 120px 1.4fr 60px 1fr 1fr 0.85fr',
            gap:0, padding:'11px 0',
            borderBottom: `1px solid ${C.line}`,
            fontSize: 13, opacity: rowAppear,
            transform: `translateY(${(1-rowAppear)*8}px)`,
            background: r.planRow ? 'rgba(201,162,39,0.04)' : 'transparent',
          }}>
            <div>
              <span style={{
                width: 22, height: 22, borderRadius: 4,
                background: r.src === 'E' ? 'rgba(201,162,39,0.2)' : 'rgba(47,109,225,0.2)',
                border: `1px solid ${r.src === 'E' ? 'rgba(201,162,39,0.5)' : 'rgba(47,109,225,0.5)'}`,
                color: r.src === 'E' ? C.gold : C.accent2,
                fontFamily: mono, fontSize: 11, fontWeight: 700,
                display:'inline-grid', placeItems:'center',
              }}>{r.src}</span>
            </div>
            <div style={{ fontFamily: mono, fontSize: 11, color: C.muted, alignSelf:'center' }}>{r.code}</div>
            <div style={{ alignSelf:'center' }}>{r.desc}</div>
            <div style={{ fontFamily: mono, fontSize: 11, color: C.muted, alignSelf:'center' }}>{r.type}</div>
            <div style={{ textAlign:'right', fontFamily: mono, fontSize: 13, color: C.muted, alignSelf:'center' }}>{r.plan}</div>
            <div style={{ textAlign:'right', fontFamily: mono, fontSize: 13, alignSelf:'center' }}>{r.act}</div>
            <div style={{
              textAlign:'right', fontFamily: mono, fontSize: 12,
              color: r.ok ? C.ok : C.red, alignSelf:'center',
            }}>{r.dv}</div>
          </div>
        );
      })}
    </div>
  );
}

function Kpi({ t, appearT, label, value, sub, bar, barColor, pos }) {
  const appear = clamp((t - appearT)/0.4, 0, 1);
  return (
    <div style={{
      padding: 14, borderRadius: 10,
      background: 'rgba(255,255,255,0.025)',
      border: `1px solid ${C.line2}`,
      opacity: appear,
      transform: `translateY(${(1-appear)*10}px)`,
    }}>
      <div style={{
        fontFamily: mono, fontSize: 10, letterSpacing:'0.16em',
        color: C.muted, marginBottom: 6,
      }}>
        {label.toUpperCase()}
      </div>
      <div style={{
        fontFamily: sans, fontSize: 28, fontWeight: 700,
        color: pos ? C.ok : C.chalk, letterSpacing:'-0.02em',
      }}>
        {value}
      </div>
      <div style={{ fontFamily: mono, fontSize: 11, color: C.muted, marginTop: 4 }}>{sub}</div>
      {bar != null && (
        <div style={{
          height: 4, background:'rgba(255,255,255,0.06)', borderRadius:2,
          marginTop: 8, overflow:'hidden',
        }}>
          <div style={{
            width: `${bar*100}%`, height:'100%', background: barColor, borderRadius: 2,
          }}/>
        </div>
      )}
    </div>
  );
}

/* ───────────────────────── SCENE 4 — The flow ───────────────────────── */

function Scene4() {
  return (
    <Sprite start={19} end={33.2}>
      {({ localTime }) => {
        // active step index based on local time
        const steps = [
          { label: tr('Requisition',    'Αίτημα'),            sub: tr('Foreman raises it from site.',      'Ο επιστάτης το ανοίγει από το εργοτάξιο.'), t0: 1.2 },
          { label: tr('Purchase Order', 'Παραγγελία'),        sub: tr('Procurement turns it into a PO.',   'Οι προμήθειες το μετατρέπουν σε PO.'),      t0: 4.0 },
          { label: tr('Goods Received', 'Παραλαβή'),          sub: tr('Site confirms what arrived.',       'Το εργοτάξιο επιβεβαιώνει τι έφτασε.'),     t0: 6.8 },
          { label: tr('Invoice match',  'Συμφωνία τιμολ.'),  sub: tr('Three-way match. Pushed to ERP.',   'Τριμερής αντιστοίχιση. Αποστολή σε ERP.'),  t0: 9.6 },
        ];
        const active = steps.reduce((acc,s,i) => localTime >= s.t0 ? i : acc, -1);
        return (
          <div style={{ position:'absolute', inset:0, background: C.ink }}>
            <GridBackdrop start={19} color="rgba(91,141,240,0.10)"/>

            <Fade start={19.1} end={32.8} fadeIn={0.4} fadeOut={0.5}>
              <div style={{ position:'absolute', top: 90, left: 80,
                fontFamily: mono, fontSize: 14, letterSpacing:'0.22em',
                color: C.accent2 }}>
                {tr('/03 — HOW IT WORKS', '/03 — ΠΩΣ ΛΕΙΤΟΥΡΓΕΙ')}
              </div>
            </Fade>

            <Fade start={19.3} end={32.8} fadeIn={0.5} fadeOut={0.5}>
              <div style={{
                position:'absolute', top: 130, left: 80, right: 80,
                fontFamily: sans, fontSize: 60, fontWeight: 600,
                color: C.chalk, letterSpacing:'-0.02em', lineHeight: 1.05,
                maxWidth: 1500,
              }}>
                {tr('From the foreman on site', 'Από τον επιστάτη στο εργοτάξιο')}<br/>
                {tr('to the ledger in your ERP.', 'στο καθολικό του ERP σας.')}
              </div>
            </Fade>

            {/* The 4 cards */}
            <FlowCards localTime={localTime} active={active} steps={steps}/>

            {/* Travelling dot on the connector */}
            <FlowConnector localTime={localTime}/>

            {/* Step caption */}
            <FlowCaption localTime={localTime} active={active} steps={steps}/>
          </div>
        );
      }}
    </Sprite>
  );
}

function FlowCards({ localTime, active, steps }) {
  // 4 cards arranged horizontally, with vertical center
  const W = 360, H = 220;
  const cardY = 460;
  const gapX = 100;
  const totalW = W*4 + gapX*3;
  const startX = (1920 - totalW)/2;
  return (
    <>
      {steps.map((s, i) => {
        const x = startX + i*(W + gapX);
        const appearT = s.t0 - 0.4;
        const appear = clamp((localTime - appearT)/0.5, 0, 1);
        const lit = i <= active;
        const justLit = active === i ? clamp((localTime - s.t0)/0.7, 0, 1) : (i < active ? 1 : 0);
        return (
          <div key={i} style={{
            position:'absolute', left: x, top: cardY,
            width: W, height: H,
            opacity: appear,
            transform: `translateY(${(1-appear)*18}px)`,
          }}>
            <FlowCard step={i+1} label={s.label} lit={lit} justLit={justLit} localTime={localTime}/>
          </div>
        );
      })}
    </>
  );
}

function FlowCard({ step, label, lit, justLit, localTime }) {
  return (
    <div style={{
      width:'100%', height:'100%',
      borderRadius: 14, padding: 20,
      background: lit
        ? 'linear-gradient(180deg, rgba(47,109,225,0.10), rgba(47,109,225,0.02))'
        : 'linear-gradient(180deg, rgba(255,255,255,0.025), rgba(255,255,255,0.005))',
      border: `1px solid ${lit ? 'rgba(47,109,225,0.45)' : C.line}`,
      boxShadow: lit ? '0 24px 60px -20px rgba(47,109,225,0.6), 0 0 0 1px rgba(47,109,225,0.15)' : 'none',
      transition: 'all 200ms',
      display:'flex', flexDirection:'column', position:'relative', overflow:'hidden',
    }}>
      {/* shimmer overlay when justLit */}
      {justLit > 0 && justLit < 1 && (
        <div style={{
          position:'absolute', inset:0,
          background: `linear-gradient(120deg, transparent ${justLit*100-20}%, rgba(91,141,240,0.25) ${justLit*100}%, transparent ${justLit*100+20}%)`,
          pointerEvents:'none',
        }}/>
      )}
      <div style={{ display:'flex', alignItems:'center', gap:8, marginBottom: 14 }}>
        <div style={{
          fontFamily: mono, fontSize: 11,
          color: lit ? C.accent2 : C.muted,
        }}>0{step}</div>
        <div style={{ flex:1, height:1, background: lit ? 'rgba(91,141,240,0.35)' : C.line }}/>
        <div style={{ fontFamily: mono, fontSize: 10, color: C.muted, letterSpacing:'0.16em' }}>STEP</div>
      </div>
      <div style={{ height: 96, display:'grid', placeItems:'center' }}>
        <FlowIcon step={step} lit={lit} t={localTime}/>
      </div>
      <div style={{
        fontFamily: sans, fontSize: 20, fontWeight: 600,
        color: lit ? C.chalk : 'rgba(232,237,245,0.6)',
        textAlign:'center', letterSpacing:'-0.01em',
      }}>{label}</div>
    </div>
  );
}

function FlowIcon({ step, lit, t }) {
  const stroke = lit ? C.accent2 : 'rgba(232,237,245,0.35)';
  const accent = lit ? C.gold : 'rgba(232,237,245,0.25)';
  const ok     = lit ? C.ok : 'rgba(232,237,245,0.25)';
  if (step === 1) {
    // clipboard
    return (
      <svg width="80" height="80" viewBox="0 0 80 80" fill="none">
        <rect x="14" y="12" width="52" height="60" rx="4" stroke={stroke} strokeWidth="2"/>
        <rect x="28" y="6"  width="24" height="12" rx="2" fill={accent}/>
        <line x1="22" y1="32" x2="58" y2="32" stroke={stroke} strokeWidth="2"/>
        <line x1="22" y1="42" x2="50" y2="42" stroke={stroke} strokeWidth="2"/>
        <line x1="22" y1="52" x2="54" y2="52" stroke={stroke} strokeWidth="2"/>
        <line x1="22" y1="62" x2="44" y2="62" stroke={stroke} strokeWidth="2"/>
      </svg>
    );
  }
  if (step === 2) {
    // PO doc with stamp
    return (
      <svg width="80" height="80" viewBox="0 0 80 80" fill="none">
        <rect x="16" y="10" width="48" height="60" rx="3" stroke={stroke} strokeWidth="2"/>
        <line x1="22" y1="22" x2="50" y2="22" stroke={stroke} strokeWidth="2"/>
        <line x1="22" y1="32" x2="58" y2="32" stroke={stroke} strokeWidth="2"/>
        <line x1="22" y1="40" x2="54" y2="40" stroke={stroke} strokeWidth="2"/>
        <line x1="22" y1="48" x2="48" y2="48" stroke={stroke} strokeWidth="2"/>
        <circle cx="52" cy="60" r="9" stroke={accent} strokeWidth="2"/>
        <path d="M47 60l4 4 7-8" stroke={accent} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
      </svg>
    );
  }
  if (step === 3) {
    // delivery box + truck arrow
    return (
      <svg width="80" height="80" viewBox="0 0 80 80" fill="none">
        <path d="M18 28 L40 18 L62 28 L62 56 L40 66 L18 56 Z" stroke={stroke} strokeWidth="2" strokeLinejoin="round"/>
        <path d="M18 28 L40 38 L62 28" stroke={stroke} strokeWidth="2" strokeLinejoin="round"/>
        <line x1="40" y1="38" x2="40" y2="66" stroke={stroke} strokeWidth="2"/>
        <path d="M4 28 L14 28" stroke={accent} strokeWidth="2" strokeLinecap="round"/>
        <path d="M10 24 L14 28 L10 32" stroke={accent} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
      </svg>
    );
  }
  if (step === 4) {
    // invoice with check
    return (
      <svg width="80" height="80" viewBox="0 0 80 80" fill="none">
        <path d="M18 10 H62 V70 L54 64 L46 70 L38 64 L30 70 L22 64 L18 70 Z"
              stroke={stroke} strokeWidth="2" strokeLinejoin="round"/>
        <line x1="24" y1="24" x2="56" y2="24" stroke={stroke} strokeWidth="2"/>
        <line x1="24" y1="34" x2="56" y2="34" stroke={stroke} strokeWidth="2"/>
        <line x1="24" y1="44" x2="44" y2="44" stroke={stroke} strokeWidth="2"/>
        <path d="M44 52 L50 58 L60 46" stroke={ok} strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"/>
      </svg>
    );
  }
  return null;
}

function FlowConnector({ localTime }) {
  const W = 360, gapX = 100;
  const totalW = W*4 + gapX*3;
  const startX = (1920 - totalW)/2;
  const y = 460 + 110; // through middle of cards
  const segStart = startX + W;
  const segEnd   = startX + totalW - W;
  // dot travel: starts at t=2.2 ends at t=10 (within scene-local 0..14)
  const dotP = clamp((localTime - 2.2) / 7.5, 0, 1);
  const dotX = segStart + (segEnd - segStart) * dotP;
  // dashed gaps between cards (3 segments)
  return (
    <>
      {[0,1,2].map(i => {
        const x = startX + W + i*(W+gapX) - gapX;
        return (
          <div key={i} style={{
            position:'absolute', left: x, top: y - 1, width: gapX, height: 2,
            backgroundImage: `linear-gradient(90deg, ${C.line2} 50%, transparent 0)`,
            backgroundSize: '10px 2px',
          }}/>
        );
      })}
      {/* moving dot */}
      <div style={{
        position:'absolute', left: dotX - 8, top: y - 8,
        width: 16, height: 16, borderRadius: 99,
        background: C.accent2,
        boxShadow: '0 0 24px 6px rgba(91,141,240,0.5)',
        opacity: localTime >= 2.0 && localTime <= 11 ? 1 : 0,
      }}/>
    </>
  );
}

function FlowCaption({ localTime, active, steps }) {
  if (active < 0) return null;
  const s = steps[active];
  const captionAppear = clamp((localTime - s.t0)/0.4, 0, 1);
  return (
    <div style={{
      position:'absolute', left: 0, right: 0, top: 740,
      textAlign:'center',
      fontFamily: sans, fontSize: 32, color: C.chalk,
      letterSpacing:'-0.01em',
      opacity: captionAppear,
      transform: `translateY(${(1-captionAppear)*10}px)`,
    }}>
      <span style={{ color: C.accent2, fontFamily: mono, fontSize: 16, letterSpacing:'0.18em' }}>
        STEP 0{active+1} ·&nbsp;
      </span>
      {s.sub}
    </div>
  );
}

/* ───────────────────────── SCENE 5 — Time saved ───────────────────────── */

function Scene5() {
  return (
    <Sprite start={33} end={37.2}>
      {({ localTime }) => {
        const oldP = clamp(localTime / 1.2, 0, 1);
        const newP = clamp((localTime - 1.4) / 0.8, 0, 1);
        return (
          <div style={{ position:'absolute', inset:0, background: C.ink }}>
            <GridBackdrop start={33} color="rgba(91,141,240,0.10)"/>

            <Fade start={33.1} end={37} fadeIn={0.3} fadeOut={0.4}>
              <div style={{
                position:'absolute', top: 120, left:0, right:0,
                textAlign:'center',
                fontFamily: mono, fontSize: 14, letterSpacing:'0.22em', color: C.accent2,
              }}>{tr('/04 — TIME GAINED', '/04 — ΧΡΟΝΟΣ ΠΟΥ ΚΕΡΔΙΖΕΤΕ')}</div>
            </Fade>

            <Fade start={33.2} end={37} fadeIn={0.4} fadeOut={0.4}>
              <div style={{
                position:'absolute', top: 170, left: 0, right: 0,
                textAlign:'center',
                fontFamily: sans, fontSize: 64, fontWeight: 600,
                color: C.chalk, letterSpacing:'-0.025em', lineHeight: 1.05,
              }}>
                {tr('From days, to minutes.', 'Από ημέρες, σε λεπτά.')}
              </div>
            </Fade>

            {/* Two columns */}
            <div style={{
              position:'absolute', top: 360, left: 0, right: 0,
              display:'flex', justifyContent:'center', gap: 120,
            }}>
              <TimeCard
                label={tr('Before', 'Πριν')}
                sub="PO → GRN → invoice match"
                value="4"
                unit={tr('days', 'ημέρες')}
                color={C.red}
                barP={oldP}
                barLen={620}
              />
              <TimeCard
                label={tr('With Operis', 'Με Operis')}
                sub="PO → GRN → invoice match"
                value="4"
                unit={tr('minutes', 'λεπτά')}
                color={C.ok}
                barP={newP}
                barLen={60}
                accent
              />
            </div>
          </div>
        );
      }}
    </Sprite>
  );
}

function TimeCard({ label, sub, value, unit, color, barP, barLen, accent }) {
  return (
    <div style={{ width: 600, fontFamily: sans, color: C.chalk }}>
      <div style={{
        fontFamily: mono, fontSize: 13, letterSpacing:'0.16em',
        color: accent ? C.accent2 : C.muted, marginBottom: 10,
      }}>{label.toUpperCase()}</div>
      <div style={{ display:'flex', alignItems:'baseline', gap: 16, marginBottom: 20 }}>
        <div style={{
          fontSize: 144, fontWeight: 700, color, letterSpacing:'-0.04em', lineHeight: 1,
        }}>{value}</div>
        <div style={{ fontSize: 36, color: C.muted, fontWeight: 500 }}>{unit}</div>
      </div>
      <div style={{
        height: 8, background:'rgba(255,255,255,0.06)', borderRadius:4, overflow:'hidden',
        marginBottom: 14,
      }}>
        <div style={{
          width: `${barP * barLen / 6.2}%`,
          height:'100%', background: color, borderRadius:4,
          transition:'width 200ms',
        }}/>
      </div>
      <div style={{ fontSize: 16, color: C.muted }}>{sub}</div>
    </div>
  );
}

/* ───────────────────────── SCENE 6 — CTA ───────────────────────── */

function Scene6() {
  return (
    <Sprite start={37} end={40}>
      {({ localTime }) => {
        return (
          <div style={{ position:'absolute', inset:0, background: C.ink }}>
            <GridBackdrop start={37} color="rgba(91,141,240,0.10)"/>
            <div style={{
              position:'absolute', inset:0,
              background:'radial-gradient(ellipse 50% 50% at 50% 60%, rgba(47,109,225,0.22), transparent 70%)',
            }}/>

            <Fade start={37.1} end={40} fadeIn={0.5} fadeOut={0.2}>
              <div style={{
                position:'absolute', top: 280, left: 0, right: 0,
                display:'flex', alignItems:'center', justifyContent:'center', gap: 24,
              }}>
                <svg width="92" height="92" viewBox="0 0 24 24">
                  <rect x="2" y="2" width="20" height="20" rx="5" fill={C.accent}/>
                  <rect x="6" y="6" width="12" height="12" rx="2" fill={C.ink}/>
                  <rect x="9" y="9" width="6" height="6" rx="1" fill={C.accent2}/>
                </svg>
                <div style={{
                  fontFamily: sans, fontSize: 96, fontWeight: 600,
                  color: C.chalk, letterSpacing:'-0.025em',
                }}>Operis</div>
              </div>
            </Fade>

            <Fade start={37.4} end={40} fadeIn={0.5} fadeOut={0.2}>
              <div style={{
                position:'absolute', top: 470, left: 0, right: 0,
                textAlign:'center',
                fontFamily: sans, fontSize: 56, fontWeight: 500,
                color: C.chalk, letterSpacing:'-0.02em',
              }}>
                {tr('Run the work, not the spreadsheet.', 'Διαχειριστείτε τη δουλειά, όχι το Excel.')}
              </div>
            </Fade>

            <Fade start={37.8} end={40} fadeIn={0.5} fadeOut={0.2}>
              <div style={{
                position:'absolute', top: 600, left:0, right:0,
                textAlign:'center',
                fontFamily: sans, fontSize: 22, color: C.muted,
              }}>
                {tr('Construction operations platform', 'Πλατφόρμα λειτουργιών κατασκευής')}
              </div>
            </Fade>

            <Fade start={38} end={40} fadeIn={0.4} fadeOut={0.2}>
              <a
                href="/demo.html"
                target="_top"
                style={{
                  position:'absolute', top: 700, left: '50%', transform:'translateX(-50%)',
                  display:'inline-flex', alignItems:'center', gap: 12,
                  padding: '18px 28px', borderRadius: 12,
                  background: C.accent, color:'#fff', textDecoration: 'none',
                  fontFamily: sans, fontSize: 22, fontWeight: 500,
                  boxShadow:'0 24px 64px -16px rgba(47,109,225,0.7), 0 0 0 1px rgba(255,255,255,0.1) inset',
                  cursor: 'pointer',
                }}>
                {tr('Book a demo', 'Κλείστε επίδειξη')}
                <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
                  <path d="M5 12h14M13 5l7 7-7 7"/>
                </svg>
              </a>
            </Fade>

            <Fade start={38.2} end={40} fadeIn={0.4} fadeOut={0.2}>
              <div style={{
                position:'absolute', bottom: 100, left: 0, right: 0,
                textAlign:'center',
                fontFamily: mono, fontSize: 13, color: C.muted, letterSpacing:'0.16em',
              }}>OPERIS.BUILD</div>
            </Fade>
          </div>
        );
      }}
    </Sprite>
  );
}

/* ───────────────────────── ROOT VIDEO ───────────────────────── */

function OperisVideo() {
  // Lang lives in window.OPERIS_LANG (read by tr() at render time).
  // We mirror it in React state so any change triggers a full re-render.
  const [, setTick] = React.useState(0);
  React.useEffect(() => {
    function readInitial() {
      const p = new URLSearchParams(location.search);
      const urlLang = p.get('lang');
      let stored = null;
      try { stored = localStorage.getItem('operis-lang'); } catch {}
      return (urlLang === 'gr' || stored === 'gr') ? 'gr' : 'en';
    }
    window.OPERIS_LANG = readInitial();
    function onMsg(e) {
      const data = e && e.data;
      if (data && data.type === 'operis-lang') {
        window.OPERIS_LANG = data.lang === 'gr' ? 'gr' : 'en';
        setTick(t => t + 1);
      }
    }
    window.addEventListener('message', onMsg);
    return () => window.removeEventListener('message', onMsg);
  }, []);
  return (
    <div data-video-root data-screen-label="t=00s" style={{ position:'absolute', inset: 0 }}>
      <Stage width={1920} height={1080} duration={40} background={C.ink} persistKey="operis-video">
        <ScreenLabel/>
        <Scene1/>
        <Scene2/>
        <Scene3/>
        <Scene4/>
        <Scene5/>
        <Scene6/>
      </Stage>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<OperisVideo/>);
