// web-mockups.jsx — Web variant, timeline-sequenced mockups
// Each phase lasts 4s (16s total across 5 phases) with sub-events scheduled
// inside. Elements appear in order and STAY — true timeline choreography.

// ═══════════════════════════════════════════════════════════════════════════
// PHASE 01 — DISCOVER: sticky notes pinned to a corkboard, one by one
// ═══════════════════════════════════════════════════════════════════════════
function WebDiscoverMockup({ localTime = 0, duration = 4 }) {
  const notes = [
    { t: 0.2, x: 50,  y: 120, rot: -3,  color: '#f4d9a0', head: '§01', text: 'Target:\nfounder-led\nB2B studios' },
    { t: 0.8, x: 260, y: 90,  rot: 2,   color: '#e8f0d9', head: '§02', text: 'Hero:\nhigh-contrast\neditorial' },
    { t: 1.4, x: 470, y: 130, rot: -2,  color: '#f5c9b3', head: '§03', text: '3-click\ncontact\nflow' },
    { t: 2.0, x: 70,  y: 330, rot: 1.5, color: '#e8f0d9', head: '§04', text: 'Case studies\n→ proof' },
    { t: 2.4, x: 300, y: 360, rot: -1,  color: '#f4d9a0', head: '§05', text: 'Book call\n= primary CTA' },
  ];
  // Arrows appear after their two notes exist
  const arrows = [
    { t: 2.8, d: 'M180,180 Q240,140 320,160' },
    { t: 3.1, d: 'M400,180 Q460,130 530,160' },
    { t: 3.4, d: 'M170,380 Q240,410 320,400' },
  ];
  // Persona card lands late
  const tPersona = 3.2;

  return (
    <div style={{
      width: '100%', height: '100%',
      background: '#ede5d3',
      backgroundImage: `
        repeating-linear-gradient(45deg, rgba(139, 105, 67, 0.04) 0 1px, transparent 1px 5px),
        repeating-linear-gradient(-45deg, rgba(139, 105, 67, 0.05) 0 1px, transparent 1px 7px)
      `,
      position: 'relative', padding: 36, boxSizing: 'border-box',
    }}>
      <div style={{
        fontFamily: DH.mono, fontSize: 12, letterSpacing: '0.14em',
        color: DH.moss600, textTransform: 'uppercase', opacity: 0.75, marginBottom: 10,
      }}>
        RESEARCH BOARD · user_flow_v3.fig
      </div>

      <div style={{ position: 'relative', width: 700, height: 520 }}>
        {/* Arrows */}
        <svg style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }} viewBox="0 0 700 520">
          <defs>
            <marker id="arr-wd" markerWidth="8" markerHeight="8" refX="6" refY="4" orient="auto">
              <path d="M0,0 L6,4 L0,8" fill="none" stroke={DH.moss600} strokeWidth="1.6"/>
            </marker>
          </defs>
          {arrows.map((a, i) => {
            const p = clamp((localTime - a.t) / 0.5, 0, 1);
            return (
              <path key={i} d={a.d} stroke={DH.moss600} strokeWidth="1.6"
                fill="none" markerEnd="url(#arr-wd)" strokeDasharray="5 4"
                strokeDashoffset={(1 - p) * 120} opacity={p}/>
            );
          })}
        </svg>

        {notes.map((n, i) => {
          const p = clamp((localTime - n.t) / 0.35, 0, 1);
          const ease = Easing.easeOutCubic(p);
          return (
            <div key={i} style={{
              position: 'absolute', left: n.x, top: n.y,
              width: 175, height: 165, background: n.color,
              padding: 14, boxSizing: 'border-box',
              transform: `rotate(${n.rot * ease}deg) scale(${0.6 + 0.4 * ease}) translateY(${(1 - ease) * -20}px)`,
              opacity: p,
              boxShadow: '2px 5px 10px rgba(0,0,0,0.1), inset 0 -2px 0 rgba(0,0,0,0.04)',
              fontFamily: "'Caveat', cursive", fontSize: 20, lineHeight: 1.22,
              color: '#2a2620', whiteSpace: 'pre-line',
              willChange: 'transform, opacity',
            }}>
              <div style={{ fontSize: 10, color: DH.moss600, opacity: 0.7, marginBottom: 6, fontFamily: DH.mono, letterSpacing: '0.1em' }}>
                {n.head}
              </div>
              {n.text}
              {/* pin */}
              <div style={{
                position: 'absolute', left: '50%', top: -6, transform: 'translateX(-50%)',
                width: 10, height: 10, borderRadius: 5,
                background: 'radial-gradient(circle at 30% 30%, #ef5a5a, #941a1a)',
                boxShadow: '0 2px 3px rgba(0,0,0,0.3)',
              }}/>
            </div>
          );
        })}
      </div>

      {/* Persona card */}
      {localTime >= tPersona - 0.1 && (() => {
        const p = clamp((localTime - tPersona) / 0.5, 0, 1);
        const ease = Easing.easeOutCubic(p);
        return (
          <div style={{
            position: 'absolute', right: 40, top: 100, width: 300,
            background: '#fff', borderRadius: 12, padding: 22,
            boxShadow: '0 14px 34px rgba(36, 69, 58, 0.12)',
            transform: `translateY(${(1 - ease) * 20}px)`, opacity: p,
          }}>
            <div style={{ fontFamily: DH.mono, fontSize: 10, letterSpacing: '0.14em', color: DH.moss600, textTransform: 'uppercase', marginBottom: 12 }}>
              PERSONA · 01
            </div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 14, marginBottom: 14 }}>
              <div style={{ width: 54, height: 54, borderRadius: 27, background: `linear-gradient(135deg, ${DH.moss500}, ${DH.moss700})` }}/>
              <div>
                <div style={{ fontFamily: DH.display, fontWeight: 600, fontSize: 18, color: DH.ink }}>Maya · 34</div>
                <div style={{ fontFamily: DH.body, fontSize: 12, color: DH.ink, opacity: 0.6 }}>Founder, venture studio</div>
              </div>
            </div>
            <div style={{ fontFamily: DH.body, fontSize: 13, color: DH.ink, opacity: 0.82, lineHeight: 1.55 }}>
              <div style={{ marginBottom: 8 }}>
                <span style={{ color: DH.moss600, fontWeight: 600, fontFamily: DH.mono, fontSize: 10, letterSpacing: '0.1em' }}>GOAL · </span>
                Credibility in 2 weeks
              </div>
              <div>
                <span style={{ color: DH.amber, fontWeight: 600, fontFamily: DH.mono, fontSize: 10, letterSpacing: '0.1em' }}>FRICTION · </span>
                Generic agency sites
              </div>
            </div>
          </div>
        );
      })()}

      {/* Status strip at bottom */}
      <div style={{
        position: 'absolute', left: 36, bottom: 20,
        fontFamily: DH.mono, fontSize: 11, color: DH.moss600, letterSpacing: '0.1em',
        opacity: clamp(localTime - 0.1, 0, 1),
      }}>
        ● notes: {notes.filter(n => localTime >= n.t).length}/5 pinned
      </div>
    </div>
  );
}

// ═══════════════════════════════════════════════════════════════════════════
// PHASE 02 — DESIGN: wireframe on left, wipe reveals hi-fi on right
// The seam moves left→right across the phase, revealing the polished version
// ═══════════════════════════════════════════════════════════════════════════
function WebDesignMockup({ localTime = 0, duration = 4 }) {
  // Wipe travels from 100% (all wireframe) to 0% (all hi-fi) between t=1.0 and t=3.2
  const wipeP = clamp((localTime - 1.0) / 2.2, 0, 1);
  const wireframeWidth = (1 - Easing.easeInOutCubic(wipeP)) * 100; // % of viewport covered by wireframe
  // Annotation dot appears, cursor clicks CTA
  const tAnnot = 0.6;
  const tStamp = 3.4;

  return (
    <div style={{ width: '100%', height: '100%', background: '#fafaf8', position: 'relative', overflow: 'hidden' }}>
      {/* Figma chrome */}
      <div style={{ height: 36, background: '#2c2c2c', color: '#ccc', fontFamily: DH.mono, fontSize: 11,
        display: 'flex', alignItems: 'center', padding: '0 16px', gap: 16 }}>
        <div style={{ display: 'flex', gap: 6 }}>
          {['#ff5f57','#febc2e','#28c840'].map((c, i) => <div key={i} style={{ width: 10, height: 10, borderRadius: 5, background: c }}/>)}
        </div>
        <div style={{ opacity: 0.6 }}>digital_heroes — hero-v4.fig</div>
        <div style={{ marginLeft: 'auto', display: 'flex', gap: 14, opacity: 0.6 }}>
          <span>Design</span><span>Prototype</span><span>Inspect</span>
        </div>
      </div>

      {/* Hi-fi bottom layer (always there) */}
      <div style={{ position: 'absolute', top: 36, left: 0, right: 0, bottom: 0, background: DH.bg,
        padding: 36, boxSizing: 'border-box' }}>
        <div style={{ fontFamily: DH.mono, fontSize: 11, color: DH.moss600, letterSpacing: '0.12em', textTransform: 'uppercase', marginBottom: 18 }}>
          HI-FI · v2.0
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 18, marginBottom: 30 }}>
          <div style={{ fontFamily: DH.display, fontWeight: 700, fontSize: 16, color: DH.ink }}>digital.<span style={{ opacity: 0.55 }}>HEROES</span></div>
          <div style={{ marginLeft: 'auto', display: 'flex', gap: 20, fontSize: 13, color: DH.ink, opacity: 0.7 }}>
            <span>Work</span><span>Services</span><span>About</span>
          </div>
          <div style={{ background: DH.moss600, color: '#fff', padding: '8px 16px', borderRadius: 18, fontSize: 12, fontWeight: 500 }}>Contact</div>
        </div>
        <div style={{ fontFamily: DH.display, fontWeight: 700, fontSize: 76, lineHeight: 0.94, color: DH.ink, letterSpacing: '-0.03em' }}>
          Sites that
        </div>
        <div style={{ fontFamily: DH.display, fontWeight: 700, fontSize: 76, lineHeight: 0.94, color: DH.ink }}>
          <span style={{ fontFamily: DH.serif, fontStyle: 'italic', fontWeight: 400, color: DH.moss600 }}>ship.</span>
        </div>
        <div style={{ fontSize: 16, color: DH.ink, opacity: 0.72, marginTop: 18, lineHeight: 1.55, maxWidth: 460 }}>
          Editorial-grade marketing pages, delivered on a clear schedule.
        </div>
        <div style={{ marginTop: 24, display: 'flex', gap: 12 }}>
          <div style={{ background: DH.moss600, color: '#fff', padding: '12px 22px', borderRadius: 24, fontSize: 14, fontWeight: 500, position: 'relative' }}>
            Start a project →
          </div>
          <div style={{ border: `1px solid ${DH.ruleStrong}`, color: DH.ink, padding: '11px 22px', borderRadius: 24, fontSize: 14, fontWeight: 500 }}>
            View work
          </div>
        </div>
        {/* Accent orb */}
        <div style={{ position: 'absolute', right: 60, top: 120, width: 260, height: 260, borderRadius: '50%',
          background: `radial-gradient(circle at 35% 35%, ${DH.moss500}, ${DH.moss700})` }}/>
      </div>

      {/* Wireframe top layer — fills the frame but is clipped so that only the
          RIGHT portion is visible. As the wipe progresses, the left edge of the
          visible wireframe moves rightward, revealing the hi-fi underneath from
          the left. Content inside stays anchored so it isn't "pushed" right. */}
      <div style={{ position: 'absolute', top: 36, left: 0, right: 0, bottom: 0,
        background: '#f2efe8',
        padding: 36, boxSizing: 'border-box', overflow: 'hidden',
        clipPath: `inset(0 0 0 ${100 - wireframeWidth}%)`,
        borderLeft: 'none',
      }}>
        <div style={{ fontFamily: DH.mono, fontSize: 11, color: '#888', letterSpacing: '0.1em', textTransform: 'uppercase', marginBottom: 18 }}>
          WIREFRAME · v0.3
        </div>
        {/* Nav */}
        <div style={{ display: 'flex', gap: 10, marginBottom: 28, width: 900 }}>
          <div style={{ width: 80, height: 16, background: '#bab3a1', borderRadius: 2 }}/>
          {[0,1,2].map(i => <div key={i} style={{ width: 50, height: 16, background: '#ddd7c9', borderRadius: 2 }}/>)}
          <div style={{ width: 70, height: 16, background: '#bab3a1', borderRadius: 2, marginLeft: 'auto' }}/>
        </div>
        <div style={{ width: 600, height: 40, background: '#bab3a1', borderRadius: 3, marginBottom: 14 }}/>
        <div style={{ width: 500, height: 40, background: '#bab3a1', borderRadius: 3, marginBottom: 14 }}/>
        <div style={{ width: 380, height: 40, background: '#bab3a1', borderRadius: 3, marginBottom: 28 }}/>
        <div style={{ width: 560, height: 12, background: '#ddd7c9', borderRadius: 2, marginBottom: 7 }}/>
        <div style={{ width: 520, height: 12, background: '#ddd7c9', borderRadius: 2, marginBottom: 7 }}/>
        <div style={{ width: 420, height: 12, background: '#ddd7c9', borderRadius: 2, marginBottom: 28 }}/>
        <div style={{ width: 170, height: 40, background: '#888076', borderRadius: 4 }}/>

        {/* Annotation ping */}
        {localTime >= tAnnot && (
          <div style={{ position: 'absolute', left: 600, top: 180 }}>
            <div style={{ width: 12, height: 12, borderRadius: 6, background: DH.amber,
              boxShadow: `0 0 0 ${4 + (Math.sin(localTime * 7) + 1) * 4}px rgba(205,138,75,0.25)` }}/>
            <div style={{ position: 'absolute', left: 20, top: -2, fontFamily: "'Caveat', cursive", fontSize: 18, color: DH.amber, whiteSpace: 'nowrap' }}>
              more contrast here
            </div>
          </div>
        )}
      </div>

      {/* Seam cursor — sits at the seam between hi-fi (left) and wireframe (right) */}
      {wipeP > 0 && wipeP < 1 && (
        <div style={{
          position: 'absolute',
          left: `${100 - wireframeWidth}%`, top: 36,
          bottom: 0, width: 3, marginLeft: -1.5,
          background: `linear-gradient(to bottom, transparent, ${DH.moss600}, transparent)`,
        }}>
          <div style={{ position: 'absolute', left: -16, top: '50%', width: 32, height: 32, borderRadius: 16,
            background: DH.moss600, color: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center',
            fontWeight: 700, fontSize: 15, transform: 'translateY(-50%)',
            boxShadow: '0 4px 10px rgba(36,69,58,0.3)' }}>→</div>
        </div>
      )}

      {/* "Approved" stamp at end */}
      {localTime >= tStamp && (() => {
        const p = clamp((localTime - tStamp) / 0.4, 0, 1);
        return (
          <div style={{
            position: 'absolute', right: 80, bottom: 40,
            fontFamily: DH.mono, fontSize: 14, color: DH.moss600, letterSpacing: '0.2em',
            padding: '8px 16px', border: `2px solid ${DH.moss600}`, borderRadius: 4,
            transform: `rotate(-6deg) scale(${0.6 + 0.4 * Easing.easeOutCubic(p)})`,
            opacity: p,
          }}>
            § APPROVED
          </div>
        );
      })()}
    </div>
  );
}

// ═══════════════════════════════════════════════════════════════════════════
// PHASE 03 — BUILD: Storybook tiles appear in order, build progress bar fills
// ═══════════════════════════════════════════════════════════════════════════
function WebBuildMockup({ localTime = 0, duration = 4 }) {
  const tiles = [
    { type: 'heading',      label: 'Display / XL',   t: 0.3 },
    { type: 'heading-s',    label: 'Display / M',    t: 0.5 },
    { type: 'btn-primary',  label: 'Button / Primary', t: 0.7 },
    { type: 'btn-ghost',    label: 'Button / Ghost', t: 0.9 },
    { type: 'chip',         label: 'Chip',           t: 1.1 },
    { type: 'card',         label: 'Card / Work',    t: 1.3 },
    { type: 'swatch',       label: 'Color / Moss',   t: 1.5 },
    { type: 'swatch-amber', label: 'Color / Amber',  t: 1.7 },
    { type: 'input',        label: 'Input / Text',   t: 1.9 },
    { type: 'badge',        label: 'Badge / Live',   t: 2.1 },
    { type: 'divider',      label: 'Rule · 1px',     t: 2.3 },
    { type: 'avatar',       label: 'Avatar · 48',    t: 2.5 },
  ];
  const buildDone = 2.9;
  const built = tiles.filter(t => localTime >= t.t).length;
  const percent = Math.min(100, Math.round((built / tiles.length) * 100));

  return (
    <div style={{ width: '100%', height: '100%', background: '#fafaf6', display: 'flex', fontFamily: DH.body }}>
      <div style={{ width: 200, background: '#f0ece2', padding: 22, boxSizing: 'border-box', borderRight: `1px solid ${DH.rule}` }}>
        <div style={{ fontFamily: DH.mono, fontSize: 11, letterSpacing: '0.12em', color: DH.moss600, textTransform: 'uppercase', marginBottom: 16 }}>
          storybook · 4.2
        </div>
        {[
          { n: 'Foundations', c: 8 },
          { n: 'Typography', c: 6, active: true },
          { n: 'Buttons', c: 4 },
          { n: 'Cards', c: 5 },
          { n: 'Forms', c: 7 },
          { n: 'Nav', c: 3 },
        ].map((item, i) => (
          <div key={i} style={{
            padding: '8px 12px', borderRadius: 4, fontSize: 13,
            background: item.active ? DH.moss600 : 'transparent',
            color: item.active ? '#fff' : DH.ink, opacity: item.active ? 1 : 0.75,
            marginBottom: 3, display: 'flex', justifyContent: 'space-between',
          }}>
            <span>{item.n}</span>
            <span style={{ opacity: 0.6, fontFamily: DH.mono, fontSize: 11 }}>{item.c}</span>
          </div>
        ))}
      </div>

      <div style={{ flex: 1, padding: 26, position: 'relative' }}>
        {/* Build progress bar */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 14, marginBottom: 16 }}>
          <div style={{ fontFamily: DH.mono, fontSize: 11, color: DH.moss600, letterSpacing: '0.1em' }}>
            BUILD · {built}/{tiles.length} COMPONENTS
          </div>
          <div style={{ flex: 1, height: 6, background: '#e9e3d3', borderRadius: 3, overflow: 'hidden' }}>
            <div style={{ height: '100%', width: `${percent}%`, background: DH.moss600, borderRadius: 3, transition: 'width 200ms' }}/>
          </div>
          <div style={{ fontFamily: DH.mono, fontSize: 11, color: DH.ink, fontVariantNumeric: 'tabular-nums' }}>{percent}%</div>
          {localTime >= buildDone && (
            <div style={{
              padding: '3px 8px', background: DH.moss600, color: '#fff',
              borderRadius: 10, fontSize: 10, fontFamily: DH.mono, letterSpacing: '0.1em',
              opacity: clamp((localTime - buildDone) / 0.3, 0, 1),
            }}>✓ PASSED</div>
          )}
        </div>

        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 14, alignContent: 'start' }}>
          {tiles.map((t, i) => {
            const p = clamp((localTime - t.t) / 0.25, 0, 1);
            const ease = Easing.easeOutCubic(p);
            return (
              <div key={i} style={{
                aspectRatio: '1.3 / 1', background: '#fff', border: `1px solid ${DH.rule}`,
                borderRadius: 6, padding: 12, display: 'flex', flexDirection: 'column',
                justifyContent: 'center', alignItems: 'center', position: 'relative',
                opacity: p, transform: `translateY(${(1 - ease) * 12}px) scale(${0.9 + 0.1 * ease})`,
                willChange: 'transform, opacity',
              }}>
                {renderTile(t.type)}
                <div style={{ position: 'absolute', bottom: 6, left: 10,
                  fontFamily: DH.mono, fontSize: 9, color: DH.ink, opacity: 0.45, letterSpacing: '0.04em' }}>
                  {t.label}
                </div>
                {/* green check */}
                {localTime - t.t > 0.4 && (
                  <div style={{ position: 'absolute', top: 6, right: 6, width: 12, height: 12, borderRadius: 6,
                    background: DH.moss500, color: '#fff', fontSize: 8, display: 'flex', alignItems: 'center', justifyContent: 'center',
                    opacity: clamp((localTime - t.t - 0.4) * 4, 0, 1),
                  }}>✓</div>
                )}
              </div>
            );
          })}
        </div>
      </div>
    </div>
  );
}
function renderTile(type) {
  switch (type) {
    case 'heading':      return <div style={{ fontFamily: DH.display, fontWeight: 700, fontSize: 36, color: DH.ink, letterSpacing: '-0.02em' }}>Aa</div>;
    case 'heading-s':    return <div style={{ fontFamily: DH.serif, fontStyle: 'italic', fontSize: 36, color: DH.moss600 }}>Aa</div>;
    case 'btn-primary':  return <div style={{ background: DH.moss600, color: '#fff', padding: '9px 16px', borderRadius: 18, fontSize: 12, fontWeight: 500 }}>Start →</div>;
    case 'btn-ghost':    return <div style={{ border: `1px solid ${DH.ruleStrong}`, color: DH.ink, padding: '8px 16px', borderRadius: 18, fontSize: 12, fontWeight: 500 }}>View</div>;
    case 'chip':         return <div style={{ background: DH.bg, color: DH.moss600, padding: '5px 11px', borderRadius: 11, fontSize: 10, fontFamily: DH.mono, letterSpacing: '0.08em' }}>§ LIVE</div>;
    case 'card':         return <div style={{ width: '82%', height: 58, background: `linear-gradient(135deg, ${DH.moss600}, ${DH.moss700})`, borderRadius: 4 }}/>;
    case 'swatch':       return <div style={{ width: 50, height: 50, background: DH.moss500, borderRadius: '50%' }}/>;
    case 'swatch-amber': return <div style={{ width: 50, height: 50, background: DH.amber, borderRadius: '50%' }}/>;
    case 'input':        return <div style={{ width: '85%', height: 28, background: '#faf7f1', border: `1px solid ${DH.rule}`, borderRadius: 4, padding: '0 10px', display: 'flex', alignItems: 'center', fontSize: 11, color: DH.ink, opacity: 0.5 }}>hello@…</div>;
    case 'badge':        return <div style={{ display: 'flex', alignItems: 'center', gap: 5, fontSize: 11, fontFamily: DH.mono, color: DH.moss600 }}><span style={{ width: 7, height: 7, borderRadius: 4, background: DH.moss500 }}/>LIVE</div>;
    case 'divider':      return <div style={{ width: '78%', height: 1, background: DH.ruleStrong }}/>;
    case 'avatar':       return <div style={{ width: 48, height: 48, borderRadius: '50%', background: `linear-gradient(135deg, ${DH.amber}, ${DH.moss600})` }}/>;
    default: return null;
  }
}

// ═══════════════════════════════════════════════════════════════════════════
// PHASE 04 — LAUNCH: marketing page builds — nav → H1 → body → CTA → deploy
// ═══════════════════════════════════════════════════════════════════════════
function WebLaunchMockup({ localTime = 0, duration = 4 }) {
  const time = useTime();
  const T_NAV = 0.2, T_H1_A = 0.5, T_H1_B = 0.9, T_BODY = 1.3,
        T_CTA = 1.7, T_VIS = 2.1, T_DEPLOY = 2.6, T_SHIPPED = 3.2;

  // cursor path: (1380, 560) -> sits near CTA then clicks
  const cursorOn = Math.floor(time * 2) % 2 === 0;

  return (
    <div style={{ width: '100%', height: '100%', background: DH.bg, position: 'relative', overflow: 'hidden' }}>
      {/* Nav */}
      <div style={{
        display: 'flex', alignItems: 'center', gap: 20, padding: '22px 40px',
        fontFamily: DH.body, fontSize: 14,
        opacity: clamp((localTime - T_NAV) / 0.4, 0, 1),
        transform: `translateY(${(1 - clamp((localTime - T_NAV) / 0.4, 0, 1)) * -8}px)`,
      }}>
        <div style={{ fontFamily: DH.display, fontWeight: 700, color: DH.ink, fontSize: 16 }}>
          digital.<span style={{ opacity: 0.55 }}>HEROES</span>
        </div>
        <div style={{ marginLeft: 'auto', display: 'flex', gap: 26, color: DH.ink, opacity: 0.7 }}>
          <span>Work</span><span>Services</span><span>Studio</span><span>Journal</span>
        </div>
        <div style={{ background: DH.moss600, color: '#fff', padding: '9px 18px', borderRadius: 20, fontWeight: 500, fontSize: 13 }}>
          Book a call →
        </div>
      </div>

      {/* Hero */}
      <div style={{ display: 'grid', gridTemplateColumns: '1.1fr 1fr', gap: 40, padding: '14px 40px 0' }}>
        <div>
          <div style={{
            fontFamily: DH.mono, fontSize: 12, color: DH.moss600, letterSpacing: '0.16em', textTransform: 'uppercase',
            marginBottom: 18, opacity: clamp((localTime - T_NAV - 0.2) / 0.4, 0, 1),
          }}>
            § READY FOR LAUNCH · MISSION · BRAND GROWTH
          </div>
          <div style={{ fontFamily: DH.display, fontWeight: 700, fontSize: 92, lineHeight: 0.92, color: DH.ink, letterSpacing: '-0.03em' }}>
            <div style={{ opacity: clamp((localTime - T_H1_A) / 0.4, 0, 1), transform: `translateY(${(1 - clamp((localTime - T_H1_A) / 0.4, 0, 1)) * 14}px)` }}>
              Sites that
            </div>
            <div style={{
              fontFamily: DH.serif, fontStyle: 'italic', fontWeight: 400, color: DH.moss600,
              opacity: clamp((localTime - T_H1_B) / 0.4, 0, 1),
              transform: `translateY(${(1 - clamp((localTime - T_H1_B) / 0.4, 0, 1)) * 14}px)`,
            }}>
              ship.
            </div>
          </div>
          <div style={{
            fontFamily: DH.body, fontSize: 15, color: DH.ink, opacity: 0.75 * clamp((localTime - T_BODY) / 0.5, 0, 1),
            marginTop: 22, lineHeight: 1.55, maxWidth: 430,
            transform: `translateY(${(1 - clamp((localTime - T_BODY) / 0.5, 0, 1)) * 10}px)`,
          }}>
            <span style={{ fontFamily: DH.serif, fontStyle: 'italic', fontSize: 22 }}>W</span>e craft <span style={{ fontFamily: DH.serif, fontStyle: 'italic' }}>tailored</span> digital experiences — design, development, growth — delivered on a clear schedule.
          </div>
          <div style={{
            marginTop: 26, display: 'flex', gap: 12,
            opacity: clamp((localTime - T_CTA) / 0.4, 0, 1),
            transform: `translateY(${(1 - clamp((localTime - T_CTA) / 0.4, 0, 1)) * 10}px)`,
            position: 'relative',
          }}>
            <div style={{ background: DH.moss600, color: '#fff', padding: '13px 24px', borderRadius: 24, fontSize: 14, fontWeight: 500, position: 'relative' }}>
              Start launch sequence →
              {/* Cursor blinking + click ripple after shipping */}
              {localTime > T_SHIPPED + 0.1 && (
                <div style={{ position: 'absolute', right: -28, top: '50%', transform: 'translateY(-50%)', width: 16, height: 16 }}>
                  <svg viewBox="0 0 14 14" fill={DH.ink} style={{ opacity: cursorOn ? 1 : 0.4 }}>
                    <path d="M2 2l8 3.5-3 1-1 3.5L2 2z"/>
                  </svg>
                </div>
              )}
            </div>
            <div style={{ border: `1px solid ${DH.ruleStrong}`, color: DH.ink, padding: '12px 24px', borderRadius: 24, fontSize: 14, fontWeight: 500 }}>
              View work
            </div>
          </div>
        </div>

        {/* Right visual block */}
        <div style={{
          position: 'relative', height: 340,
          opacity: clamp((localTime - T_VIS) / 0.5, 0, 1),
          transform: `translateY(${(1 - clamp((localTime - T_VIS) / 0.5, 0, 1)) * 14}px)`,
        }}>
          <div style={{ position: 'absolute', right: 20, top: 20, width: 300, height: 300, borderRadius: '50%',
            background: `radial-gradient(circle at 35% 35%, ${DH.moss500}, ${DH.moss700})` }}/>
          <div style={{
            position: 'absolute', right: 60, top: 80, width: 280, height: 170,
            background: '#0f1713', borderRadius: 10, padding: 18, boxSizing: 'border-box',
            display: 'flex', flexDirection: 'column', justifyContent: 'space-between', color: '#fff',
          }}>
            <div style={{ fontFamily: DH.mono, fontSize: 10, letterSpacing: '0.12em', opacity: 0.7 }}>2,000+ BRANDS</div>
            <div style={{ fontFamily: DH.display, fontWeight: 500, fontSize: 20, color: DH.amber, textAlign: 'center', lineHeight: 1.2 }}>build your next<br/>big thing</div>
            <div style={{ fontFamily: DH.mono, fontSize: 10, letterSpacing: '0.12em', opacity: 0.7, textAlign: 'right' }}>55+ COUNTRIES</div>
          </div>
          <div style={{ position: 'absolute', right: 10, bottom: 10, width: 70, height: 70, borderRadius: '50%',
            background: `radial-gradient(circle at 30% 30%, #e8a464, ${DH.amber} 60%, #8b5a2e)`,
            boxShadow: '0 8px 18px rgba(139, 90, 46, 0.3)' }}/>
        </div>
      </div>

      {/* Deploy terminal strip appears near end */}
      {localTime >= T_DEPLOY && (() => {
        const p = clamp((localTime - T_DEPLOY) / 0.6, 0, 1);
        const lines = [
          { t: T_DEPLOY, txt: '$ vercel --prod' },
          { t: T_DEPLOY + 0.3, txt: 'Building... ✓' },
          { t: T_DEPLOY + 0.55, txt: 'Deploying... ✓' },
          { t: T_SHIPPED, txt: '✓ Live at digitalheroes.com' },
        ];
        return (
          <div style={{
            position: 'absolute', left: 40, bottom: 30,
            width: 420, background: 'rgba(15,23,19,0.93)', color: '#e0dccf',
            fontFamily: DH.mono, fontSize: 11, padding: 14, borderRadius: 6,
            opacity: p, transform: `translateY(${(1 - p) * 12}px)`,
          }}>
            {lines.filter(l => localTime >= l.t).map((l, i) => (
              <div key={i} style={{ color: l.txt.startsWith('✓') ? DH.moss500 : '#e0dccf', lineHeight: 1.6 }}>
                {l.txt}
              </div>
            ))}
          </div>
        );
      })()}

      {/* SHIPPED chip */}
      {localTime >= T_SHIPPED && (
        <div style={{
          position: 'absolute', top: 24, right: 32,
          display: 'flex', alignItems: 'center', gap: 8,
          fontFamily: DH.mono, fontSize: 12, color: DH.moss600, letterSpacing: '0.16em',
          opacity: clamp((localTime - T_SHIPPED) / 0.3, 0, 1),
        }}>
          <span style={{ width: 10, height: 10, borderRadius: 5, background: DH.moss500,
            boxShadow: `0 0 ${10 + Math.sin(time * 6) * 5}px ${DH.moss500}` }}/>
          SHIPPED · v1.0
        </div>
      )}
    </div>
  );
}

// ═══════════════════════════════════════════════════════════════════════════
// PHASE 05 — OPTIMIZE: funnel fills sequentially, chart draws, metric ticks up
// ═══════════════════════════════════════════════════════════════════════════
function WebOptimizeMockup({ localTime = 0, duration = 4 }) {
  const funnel = [
    { label: 'Visitors',  v: 48240, w: 100, t: 0.3, color: DH.moss500 },
    { label: 'Engaged',   v: 19870, w: 72,  t: 0.8, color: DH.moss500 },
    { label: 'Signups',   v: 2140,  w: 48,  t: 1.3, color: DH.moss600 },
    { label: 'Activated', v: 1370,  w: 32,  t: 1.8, color: DH.moss700 },
  ];
  const T_CHART = 1.2, T_CHART_DONE = 2.6, T_METRIC = 2.8, T_ANNOT = 3.4;

  const chartPts = [[0,58],[1,55],[2,48],[3,50],[4,42],[5,38],[6,30],[7,32],[8,26],[9,20],[10,18],[11,12]];
  const maxX = 11, maxY = 60;
  const chartProg = clamp((localTime - T_CHART) / (T_CHART_DONE - T_CHART), 0, 1);
  const metricProg = clamp((localTime - T_METRIC) / 0.8, 0, 1);

  return (
    <div style={{ width: '100%', height: '100%', background: '#fff', padding: 30, boxSizing: 'border-box', position: 'relative', fontFamily: DH.body }}>
      <div style={{ display: 'flex', alignItems: 'center', marginBottom: 22 }}>
        <div>
          <div style={{ fontFamily: DH.mono, fontSize: 11, color: DH.moss600, letterSpacing: '0.14em', textTransform: 'uppercase' }}>
            FUNNEL · LAST 30 DAYS
          </div>
          <div style={{ fontFamily: DH.display, fontWeight: 600, fontSize: 24, color: DH.ink, marginTop: 5 }}>
            Lifecycle overview
          </div>
        </div>
        <div style={{ marginLeft: 'auto', display: 'flex', gap: 8 }}>
          {['7d', '30d', '90d'].map((r, i) => (
            <div key={i} style={{
              padding: '6px 14px', borderRadius: 14, fontSize: 12,
              background: i === 1 ? DH.moss600 : 'transparent',
              color: i === 1 ? '#fff' : DH.ink,
              border: i === 1 ? 'none' : `1px solid ${DH.rule}`,
            }}>{r}</div>
          ))}
        </div>
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1.1fr', gap: 24, height: 'calc(100% - 80px)' }}>
        {/* Funnel */}
        <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
          {funnel.map((f, i) => {
            const p = clamp((localTime - f.t) / 0.6, 0, 1);
            const w = Easing.easeOutCubic(p) * f.w;
            return (
              <div key={i}>
                <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 13, color: DH.ink, marginBottom: 5 }}>
                  <span style={{ opacity: 0.75 }}>{f.label}</span>
                  <span style={{ fontFamily: DH.mono, fontVariantNumeric: 'tabular-nums' }}>
                    {Math.round(f.v * p).toLocaleString()}
                  </span>
                </div>
                <div style={{ width: '100%', height: 32, background: '#f5f0e8', borderRadius: 4 }}>
                  <div style={{ width: `${w}%`, height: '100%', background: f.color, borderRadius: 4 }}/>
                </div>
              </div>
            );
          })}
          <div style={{
            marginTop: 8, padding: '14px 16px', background: DH.bg, borderRadius: 6,
            display: 'flex', alignItems: 'baseline', justifyContent: 'space-between',
            opacity: clamp((localTime - T_METRIC) / 0.3, 0, 1),
          }}>
            <div style={{ fontSize: 11, fontFamily: DH.mono, color: DH.moss600, letterSpacing: '0.12em' }}>
              ACTIVATION · RATE
            </div>
            <div style={{ fontFamily: DH.display, fontWeight: 700, fontSize: 26, color: DH.ink, fontVariantNumeric: 'tabular-nums' }}>
              {(2.84 * Easing.easeOutCubic(metricProg)).toFixed(2)}%
              {localTime >= T_METRIC + 0.6 && <span style={{ fontSize: 13, color: DH.moss600, marginLeft: 8 }}>↑ 1.60</span>}
            </div>
          </div>
        </div>

        {/* Chart */}
        <div style={{ background: '#fafaf6', border: `1px solid ${DH.rule}`, borderRadius: 6, padding: '18px 20px', position: 'relative' }}>
          <div style={{ fontSize: 11, fontFamily: DH.mono, color: DH.moss600, letterSpacing: '0.12em' }}>
            BOUNCE · TREND
          </div>
          <div style={{ fontFamily: DH.display, fontWeight: 700, fontSize: 28, color: DH.ink, marginTop: 3, fontVariantNumeric: 'tabular-nums' }}>
            {(18.4 + (1 - chartProg) * 12).toFixed(1)}%
            {chartProg >= 0.99 && <span style={{ fontSize: 13, color: DH.moss600, marginLeft: 8, fontWeight: 500 }}>↓ 12</span>}
          </div>
          <svg viewBox="0 0 320 140" style={{ width: '100%', marginTop: 14 }}>
            {[0, 20, 40, 60].map(g => <line key={g} x1="0" x2="320" y1={130 - g * 1.8} y2={130 - g * 1.8} stroke={DH.rule}/>)}
            <path
              d={chartPts.map(([x, y], i) => {
                const px = (x / maxX) * 310 + 5;
                const py = 125 - (y / maxY) * 105;
                return `${i === 0 ? 'M' : 'L'}${px},${py}`;
              }).join(' ')}
              stroke={DH.moss600} strokeWidth="2.5" fill="none"
              strokeDasharray="500" strokeDashoffset={(1 - chartProg) * 500}
            />
            <path
              d={chartPts.map(([x, y], i) => {
                const px = (x / maxX) * 310 + 5;
                const py = 125 - (y / maxY) * 105;
                return `${i === 0 ? 'M' : 'L'}${px},${py}`;
              }).join(' ') + ` L315,125 L5,125 Z`}
              fill={DH.moss500} fillOpacity={0.14 * chartProg}
            />
            {chartProg >= 1 && (
              <circle cx={(chartPts[chartPts.length - 1][0] / maxX) * 310 + 5}
                cy={125 - (chartPts[chartPts.length - 1][1] / maxY) * 105}
                r="5" fill={DH.amber}/>
            )}
          </svg>
          {/* Annotation callout */}
          {localTime >= T_ANNOT && (() => {
            const p = clamp((localTime - T_ANNOT) / 0.5, 0, 1);
            return (
              <div style={{
                position: 'absolute', right: 28, bottom: 60,
                padding: '6px 10px', background: DH.amber, color: '#fff',
                fontFamily: DH.mono, fontSize: 10, letterSpacing: '0.08em',
                borderRadius: 3, opacity: p,
                transform: `translateY(${(1 - p) * -6}px)`,
              }}>
                ↓ New hero shipped · wk 3
              </div>
            );
          })()}
        </div>
      </div>
    </div>
  );
}

Object.assign(window, {
  WebDiscoverMockup, WebDesignMockup, WebBuildMockup, WebLaunchMockup, WebOptimizeMockup,
});
