function CaseStudyView({ project, onNav, onOpenProject }) {
  var iframeRef = React.useRef(null);

  if (!project) {
    return (
      <ProjectsFolder onOpen={onOpenProject} />
    );
  }

  var isLocal = project.url && project.url.startsWith('/');

  return (
    <div style={{display: 'flex', flexDirection: 'column', height: '100%'}}>
      <div className="cs-toolbar">
        <button onClick={() => onNav && onNav('back')}>
          <span style={{fontSize:14, lineHeight:1}}>&#8592;</span> Back
        </button>
        <button disabled>
          <span style={{fontSize:14, lineHeight:1}}>&#8594;</span> Forward
        </button>
        <button onClick={() => onNav && onNav('home')}>&#8962; Home</button>
        <button onClick={() => { if (iframeRef.current) iframeRef.current.src = iframeRef.current.src; }}>&#8635; Refresh</button>
        <div className="cs-addr">
          <span className="lbl">Address:</span>
          <div className="field">
            <img src="/icons/icon-folder.svg" alt="" />
            <span>{isLocal ? 'C:\\Portfolio\\' + project.id + project.url.slice(project.url.lastIndexOf('.')) : project.url}</span>
          </div>
        </div>
      </div>
      {isLocal ? (
        <iframe
          ref={iframeRef}
          src={project.url}
          style={{width: '100%', flex: 1, border: 'none', background: '#fff'}}
          onLoad={() => {
            try {
              var loc = iframeRef.current.contentWindow.location.pathname;
              if (loc !== project.url) {
                onNav && onNav('back');
              }
            } catch(e) {}
          }}
        />
      ) : (
        <div className="cs-content">
          <h1>{project.name}</h1>
          <div className="role">{project.role}</div>
          <a className="open-cta" href={project.url} target="_blank" rel="noopener noreferrer">
            &#9654; Open {project.name}
          </a>
          <p style={{marginTop: 16}}>{project.blurb}</p>
        </div>
      )}
    </div>
  );
}

function AboutContent() {
  return (
    <div className="about-body">
      <img className="about-avatar" src="/img/dc.jpg" alt="David Ciaffoni" style={{objectFit: 'cover'}} />
      <div className="about-text">
        <h2>David Ciaffoni</h2>
        <div className="sub">UX / UI Designer Extraordinaire</div>
        <p>
          Welcome to David's webpage. Founding designer, lead designer, fractional head of product —
          shipping products at Lime, Avail, Anchorage, Polywork, Fizz, Titan, Favorited and beyond.
        </p>
        <p>
          Double-click an icon on the desktop to read a case study. Things in the Recycle Bin
          stay in the Recycle Bin.
        </p>
        <div className="about-links">
          <a href="https://www.linkedin.com/in/david-ciaffoni/" target="_blank" rel="noopener noreferrer">LinkedIn</a>
          <a href="https://github.com/davidkc0" target="_blank" rel="noopener noreferrer">GitHub</a>
          <a href="https://dribbble.com/davidkc0" target="_blank" rel="noopener noreferrer">Dribbble</a>
          <a href="https://www.dropbox.com/scl/fi/9k7w8xd2ofp641cjlyez9/David-Ciaffoni_Senior-Designer_20260128_updated.pdf?rlkey=tiregmq2ha6ynh0a21lheam1a&st=x6ntt9dj&dl=0" target="_blank" rel="noopener noreferrer">Resume.pdf</a>
          <a href="mailto:david@bestdavid.com">Email</a>
        </div>
        <p style={{marginTop: 16, fontSize: 11, color: '#404040'}}>
          &#128128; ~ Nolite messorem timere ~ &#128128;
        </p>
      </div>
    </div>
  );
}

function ProjectsFolder({ onOpen }) {
  return (
    <div className="folder-body">
      {PROJECTS.map(p => (
        <div key={p.id} className="folder-icon" onDoubleClick={() => onOpen(p)}>
          <img src={p.icon} alt="" />
          <div className="lbl">{p.name}</div>
        </div>
      ))}
    </div>
  );
}

function SideProjectsFolder({ onOpenIllusion }) {
  var sideProjects = [
    { id: 'cicada', name: 'Cicada', icon: '/icons/icon-cicada.svg?v=14', url: 'https://cicadaresearch.io' },
    { id: 'illusion', name: 'Illusion.ai', icon: '/img/illusion_icon.png?v=14', url: null },
  ];
  return (
    <div className="folder-body">
      {sideProjects.map(p => (
        <div key={p.id} className="folder-icon" onDoubleClick={() => {
          if (p.url) window.open(p.url, '_blank');
          else if (p.id === 'illusion') onOpenIllusion && onOpenIllusion();
        }}>
          <img src={p.icon} alt="" />
          <div className="lbl">{p.name}</div>
        </div>
      ))}
    </div>
  );
}

function GamesFolder() {
  var games = [
    { id: 'barrier', name: 'barrier.exe', icon: '/img/barrier.png?v=14', url: 'https://apps.apple.com/us/app/barrier-strategy-board-game/id6762404861' },
    { id: 'singularity', name: 'singularity.exe', icon: '/img/blackhole.png?v=14', url: 'https://apps.apple.com/us/app/singularity-black-hole-arcade/id6755376129' },
  ];
  return (
    <div className="folder-body">
      {games.map(g => (
        <div key={g.id} className="folder-icon" onDoubleClick={() => window.open(g.url, '_blank')}>
          <img src={g.icon} alt="" />
          <div className="lbl">{g.name}</div>
        </div>
      ))}
    </div>
  );
}

function WritingsFolder({ onOpen }) {
  return (
    <div className="folder-body">
      {WRITINGS.map(w => (
        <div key={w.id} className="folder-icon" onDoubleClick={() => onOpen(w)}>
          <img src="/img/textfile.png" alt="" />
          <div className="lbl">{w.name}</div>
        </div>
      ))}
    </div>
  );
}

function Notepad({ writing }) {
  return (
    <div className="notepad-body">
      <h3>{writing.title}</h3>
      <div style={{whiteSpace: 'pre-wrap'}}>{writing.body}</div>
    </div>
  );
}

function Trash({ onItemClick }) {
  return (
    <div className="trash-grid">
      {TRASH.map(t => (
        <div key={t.id} className="trash-item" onDoubleClick={() => onItemClick(t)} title={t.note}>
          <img className="icn" src="/img/gear_files.png?v=14" alt="" />
          <div className="lbl">{t.name}</div>
        </div>
      ))}
    </div>
  );
}

function Guestbook({ onSend }) {
  const [name, setName] = React.useState('');
  const [email, setEmail] = React.useState('');
  const [subject, setSubject] = React.useState('Hello David');
  const [body, setBody] = React.useState('');
  return (
    <div className="mail-window" style={{padding: 0, height: '100%'}}>
      <div style={{padding: 8}}>
        <div className="mail-toolbar">
          <button onClick={() => onSend({name, email, subject, body})}>
            <div className="micon" style={{
              background: "url('/img/send_icon.png?v=14') center/contain no-repeat"
            }}></div>
            Send
          </button>
          <button onClick={() => { setName(''); setEmail(''); setSubject(''); setBody(''); }}>
            <div className="micon" style={{
              background: "url('/icons/icon-trash.svg') center/contain no-repeat"
            }}></div>
            Discard
          </button>
        </div>
        <div className="mail-fields">
          <label>To:</label>
          <input type="text" value="david@bestdavid.com" readOnly style={{background:'#dfdfdf'}} />
          <label>From:</label>
          <input type="text" value={name} onChange={e=>setName(e.target.value)} placeholder="Your name" />
          <label>Reply-To:</label>
          <input type="email" value={email} onChange={e=>setEmail(e.target.value)} placeholder="you@example.com" />
          <label>Subject:</label>
          <input type="text" value={subject} onChange={e=>setSubject(e.target.value)} />
          <label style={{alignSelf:'flex-start', paddingTop:4}}>Message:</label>
          <textarea value={body} onChange={e=>setBody(e.target.value)} placeholder="Type your message here..."></textarea>
        </div>
        <button className="mail-send" onClick={() => onSend({name, email, subject, body})}>
          &#9654; Send
        </button>
      </div>
    </div>
  );
}

var AGENT_HI_FRAMES = [
  '/img/agent_hi_1.svg', '/img/agent_hi_2.svg', '/img/agent_hi_3.svg',
  '/img/agent_hi_4.svg', '/img/agent_hi_5.svg', '/img/agent_hi_6.svg', '/img/agent_hi_7.svg',
];
var AGENT_IDLE_FRAMES = ['/img/agent.svg', '/img/agent_frame2.svg'];
var AGENT_WAITING_FRAMES = ['/img/agent_waiting1.svg?v=14', '/img/agent_waiting2.svg?v=14', '/img/agent_waiting3.svg?v=14'];

function Mascot({ message, onAction, onDismiss }) {
  const [shown, setShown] = React.useState(true);
  const [frame, setFrame] = React.useState('/img/agent_hi_1.svg');
  const phaseRef = React.useRef('hi');
  const hiIndexRef = React.useRef(0);
  const idleIndexRef = React.useRef(0);
  const waitingIndexRef = React.useRef(0);

  React.useEffect(() => {
    phaseRef.current = 'hi';
    hiIndexRef.current = 0;
    var interval = setInterval(() => {
      if (phaseRef.current === 'hi') {
        hiIndexRef.current = (hiIndexRef.current + 1) % AGENT_HI_FRAMES.length;
        setFrame(AGENT_HI_FRAMES[hiIndexRef.current]);
      } else if (phaseRef.current === 'waiting') {
        waitingIndexRef.current = (waitingIndexRef.current + 1) % AGENT_WAITING_FRAMES.length;
        setFrame(AGENT_WAITING_FRAMES[waitingIndexRef.current]);
      } else {
        idleIndexRef.current = (idleIndexRef.current + 1) % AGENT_IDLE_FRAMES.length;
        setFrame(AGENT_IDLE_FRAMES[idleIndexRef.current]);
      }
    }, 500);
    return () => clearInterval(interval);
  }, []);

  const handleInteract = (actionId) => {
    if (actionId === 'dismiss') {
      phaseRef.current = 'idle';
      onAction && onAction(actionId);
      return;
    }
    phaseRef.current = 'waiting';
    waitingIndexRef.current = 0;
    setFrame(AGENT_WAITING_FRAMES[0]);
    setTimeout(() => {
      phaseRef.current = 'idle';
      onAction && onAction(actionId);
    }, 1200);
  };

  if (!shown) return null;
  return (
    <div className="mascot" style={{ right: 24, bottom: 48 }}>
      {message && (
        <div className="mascot-bubble">
          <button className="x" onClick={() => { setShown(false); onDismiss && onDismiss(); }}>&#215;</button>
          <div>{message.text}</div>
          {message.actions && message.actions.map((a, i) => (
            <button key={i} onClick={() => handleInteract(a.id)}>{a.label}</button>
          ))}
        </div>
      )}
      <img className="mascot-char" src={frame} alt="Mickey" onClick={() => handleInteract('greet')} />
    </div>
  );
}

function Dialog({ title, icon, body, buttons, onClose }) {
  return (
    <div className="dlg-backdrop">
      <div className="dlg">
        <div className="dlg-title">
          <span>{title}</span>
          <button className="win-title-btn" onClick={onClose}>
            <svg width="8" height="8" viewBox="0 0 8 8" shapeRendering="crispEdges">
              <rect x="1" y="1" width="1" height="1" fill="#000"/><rect x="2" y="2" width="1" height="1" fill="#000"/><rect x="3" y="3" width="1" height="1" fill="#000"/><rect x="4" y="3" width="1" height="1" fill="#000"/><rect x="5" y="2" width="1" height="1" fill="#000"/><rect x="6" y="1" width="1" height="1" fill="#000"/>
              <rect x="3" y="4" width="1" height="1" fill="#000"/><rect x="4" y="4" width="1" height="1" fill="#000"/>
              <rect x="2" y="5" width="1" height="1" fill="#000"/><rect x="5" y="5" width="1" height="1" fill="#000"/>
              <rect x="1" y="6" width="1" height="1" fill="#000"/><rect x="6" y="6" width="1" height="1" fill="#000"/>
            </svg>
          </button>
        </div>
        <div className="dlg-body">
          {icon && <img className="dlg-icon" src={icon} alt="" />}
          <div><p>{body}</p></div>
        </div>
        <div className="dlg-btns">
          {(buttons || [{label:'OK', primary:true, onClick: onClose}]).map((b, i) => (
            <button key={i} className={b.primary ? 'primary' : ''} onClick={b.onClick || onClose}>{b.label}</button>
          ))}
        </div>
      </div>
    </div>
  );
}

function Screensaver() {
  const canvasRef = React.useRef(null);

  React.useEffect(() => {
    var canvas = canvasRef.current;
    if (!canvas) return;
    var ctx = canvas.getContext('2d');
    var dpr = window.devicePixelRatio || 1;
    var w = window.innerWidth;
    var h = window.innerHeight;
    function setSize() {
      w = window.innerWidth;
      h = window.innerHeight;
      canvas.width = w * dpr;
      canvas.height = h * dpr;
      canvas.style.width = w + 'px';
      canvas.style.height = h + 'px';
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    }
    setSize();

    var NUM_STARS = 500;
    var SPEED = 0.008;
    var stars = [];
    function spawn(s) {
      s.x = (Math.random() - 0.5) * 2;
      s.y = (Math.random() - 0.5) * 2;
      s.z = Math.random() * 0.9 + 0.1;
    }
    for (var i = 0; i < NUM_STARS; i++) {
      var s = {};
      spawn(s);
      stars.push(s);
    }

    var rafId;
    function draw() {
      ctx.fillStyle = '#000';
      ctx.fillRect(0, 0, w, h);
      var focal = Math.min(w, h) * 0.7;
      var cx = w / 2;
      var cy = h / 2;
      for (var i = 0; i < stars.length; i++) {
        var s = stars[i];
        s.z -= SPEED;
        if (s.z <= 0.01) { spawn(s); s.z = 1; continue; }
        var sx = s.x / s.z * focal + cx;
        var sy = s.y / s.z * focal + cy;
        if (sx < 0 || sx >= w || sy < 0 || sy >= h) {
          spawn(s);
          s.z = 1;
          continue;
        }
        var size = Math.max(1, (1 - s.z) * 3.5);
        var brightness = Math.min(255, Math.floor((1 - s.z) * 280));
        ctx.fillStyle = 'rgb(' + brightness + ',' + brightness + ',' + brightness + ')';
        ctx.fillRect(sx, sy, size, size);
      }
      rafId = requestAnimationFrame(draw);
    }
    draw();

    window.addEventListener('resize', setSize);
    return () => {
      cancelAnimationFrame(rafId);
      window.removeEventListener('resize', setSize);
    };
  }, []);

  return (
    <div className="screensaver">
      <canvas ref={canvasRef} />
    </div>
  );
}

function ScreensaverManager({ idleMs }) {
  const [active, setActive] = React.useState(false);
  const activeRef = React.useRef(false);
  activeRef.current = active;

  React.useEffect(() => {
    var timer = null;
    function onActivity() {
      if (activeRef.current) setActive(false);
      if (timer) clearTimeout(timer);
      timer = setTimeout(() => setActive(true), idleMs);
    }
    var events = ['mousemove', 'mousedown', 'keydown', 'touchstart', 'wheel'];
    events.forEach(e => window.addEventListener(e, onActivity, { passive: true }));
    onActivity();
    return () => {
      events.forEach(e => window.removeEventListener(e, onActivity));
      if (timer) clearTimeout(timer);
    };
  }, [idleMs]);

  if (!active) return null;
  return <Screensaver />;
}
