// ============================================================
// Olive Garden — window content components
// Exposed via window.* for the WindowContent resolver in app.jsx
// ============================================================

// ---------- AboutContent ----------
function AboutContent({ api }){
  return (
    <div className="about-grid">
      <div className="l">
        <div className="slabel">001 — hello</div>
        <div className="hi-display">jeongwoo<span className="dot">.</span></div>
        <div className="asub">AI Automation Engineer · Hamburg, DE</div>

        <div style={{margin:'18px 0 14px'}}>
          <p className="lead">I build <em>people-oriented</em> AI &amp; automation for workplaces. I think fast, think in systems, and always ask <em>why?</em> and <em>what's the value?</em> before <em>what?</em>.</p>
        </div>

        <p className="body-p">Background spans internal GenAI platforms, RAG pipelines, agentic systems, and the unglamorous plumbing that makes any of it survive contact with real users. I ship SSO-gated, GDPR-aware products in Python and drive adoption through training and internal champion mentoring.</p>
        <p className="body-p" style={{color:'var(--ink-2)'}}>Outside of code: crochet, watercolour, hiking, a thriving (mostly) plant collection.</p>

        <div className="divider"></div>

        <div className="stack-cols">
          <div>
            <h5>Build</h5>
            <ul>
              <li>RAG &amp; vector DB</li>
              <li>Agentic systems</li>
              <li>LLMOps &amp; eval</li>
              <li>Workflow automation</li>
            </ul>
          </div>
          <div>
            <h5>Stack</h5>
            <ul>
              <li>Python · Streamlit</li>
              <li>n8n · Supabase</li>
              <li>Azure · GCP</li>
              <li>Rhino / Grasshopper</li>
            </ul>
          </div>
        </div>
      </div>

      <div className="r">
        <div className="now">
          <div className="label">▸ Now</div>
          <div className="line"><span className="ddot"></span>Hamburg · building workflow automation at quantilope · open for coffee</div>
          <div className="now-sub" style={{color:'rgba(255,255,255,.6)', marginTop:8}}>recently visited ETH Zürich for AI Safety</div>
        </div>

        <div>
          <div className="slabel" style={{marginBottom:8}}>writing</div>
          <button className="outlink" onClick={() => api && api.openApp('writing')}>on this site →</button>
        </div>

        <div>
          <div className="slabel" style={{marginBottom:8}}>elsewhere</div>
          <div style={{display:'flex', flexDirection:'column', gap:6}}>
            <a className="outlink" href="mailto:jeongwoo.jang.k@gmail.com" contentEditable={false}>e-mail ↗</a>
            <a className="outlink" href="https://linkedin.com/in/jeongwoo-jang" contentEditable={false}>linkedin ↗</a>
            <a className="outlink" href="https://github.com/Jeo-Jang" contentEditable={false}>github ↗</a>
          </div>
        </div>

        <div style={{marginTop:'auto', fontSize:'var(--t-xs)', letterSpacing:'var(--ls-cap-sm)', color:'var(--muted)', textTransform:'uppercase'}}>
          v1.0 — built may '26
        </div>
      </div>
    </div>
  );
}

// ---------- WorkContent ----------
const PROJECTS = [
  { num:'01 / 05', metric:'30+', metricLabel:'enterprise users',
    title:'Internal GenAI Hub',
    desc:'Secure multi-page Streamlit platform serving 20+ tools across global offices. Hub-and-spoke architecture decouples tool logic from orchestration. SSO via Microsoft Entra ID, Supabase RLS, 30-day auto-purge.',
    tags:['Streamlit','SSO','RAG','LLMOps'],
    link:'https://github.com/Jeo-Jang/Portfolio/blob/main/gen-ai-hub/architecture.md' },
  { num:'02 / 05', metric:'60%', metricLabel:'processing time cut',
    title:'ESG Analytics Pipeline',
    desc:'RAG pipeline for DAX40 / Fortune 100 sustainability reports. Multimodal PDF ingestion, layout-aware extraction, retrieval-optimised chunking. Outputs used in Handelsblatt publications.',
    tags:['RAG','Langflow','Vector DB','Multimodal'] },
  { num:'03 / 05', metric:'~30h', metricLabel:'saved per month',
    title:'Hybrid Workflow Orchestration',
    desc:'Automated content intelligence pipeline (n8n + Python + Airtable) with human-in-the-loop review gates. Replaced ~30 hours of monthly executive drafting effort.',
    tags:['n8n','HIL','Airtable','Python'],
    link:'https://github.com/Jeo-Jang/Portfolio/tree/main/n8n-workflows/product-carbon-footprint' },
  { num:'04 / 05', metric:'40%', metricLabel:'token cost reduction',
    title:'LLM Cost Optimisation',
    desc:'Heuristics-driven system to dynamically adjust reasoning and thinking budgets per request type. Reduced token spend by ~40% across the platform without sacrificing output quality.',
    tags:['FinOps','Heuristics','LLMOps'],
    link:'https://github.com/Jeo-Jang/Portfolio/blob/main/gen-ai-hub/docs/heuristics.md' },
  { num:'05 / 05', metric:'SDK', metricLabel:'OpenAI Agents',
    title:'Agentic ISO / Circularity Assistant',
    desc:'Standards and circularity assistant using OpenAI Agents SDK with Pydantic schema validation and retrieval grounding. Reduces hallucination risk and accelerates requirements refinement.',
    tags:['Agents','Pydantic','RAG','Guardrails'],
    link:'https://github.com/Jeo-Jang/Portfolio/blob/main/gen-ai-hub/docs/agents.md' },
];

function WorkContent({api}){
  return (
    <React.Fragment>
      <div className="fmeta">
        <span>folder contents</span>
        <span className="count"><span className="n">{PROJECTS.length}</span> projects</span>
      </div>
      <div>
        {PROJECTS.map(p => (
          <article key={p.num} className="project">
            <div>
              <div className="num">{p.num}</div>
              <div className="met">{p.metric}</div>
              <div className="met-l">{p.metricLabel}</div>
            </div>
            <div>
              <div className="title">{p.title}</div>
              <div className="desc">{p.desc}</div>
              <div className="tag-row">
                {p.tags.map(t => <span key={t} className="tag">{t}</span>)}
                {p.link && <a className="tag tag-link" href={p.link} target="_blank" rel="noopener noreferrer">↗ code</a>}
              </div>
            </div>
          </article>
        ))}
      </div>
    </React.Fragment>
  );
}

// ---------- ExperienceContent ----------
const EXPERIENCE = [
  {
    yr:'Jun 2026 →',
    role:'AI Automation Engineer',
    place:'quantilope GmbH · Hamburg (hybrid/remote)',
    note:'cross-functional process automation · n8n · agentic workflows · Salesforce / Marketo integrations',
  },
  {
    yr:'Mar 2023 — May 2026',
    role:'AI Solutions Architect / Computational Designer',
    place:'INDEED Innovation GmbH · Hamburg',
    note:'internal GenAI hub (20+ tools, 30+ users) · ESG RAG pipeline · agentic systems · SSO/GDPR · FinOps',
  },
  {
    yr:'Dec 2021 — Feb 2023',
    role:'Computational Designer',
    place:'INDEED Innovation GmbH · Hamburg',
    note:'Midjourney / DALL-E workflows (50k+ image sets) · parametric automation · LCA tooling · C# / Python scripting',
  },
  {
    yr:'Jul — Sep 2021',
    role:'Freelance Generative Designer',
    place:'INDEED Innovation GmbH · Hamburg',
    note:'3-month pilot validating computational design methods → permanent hire',
  },
  {
    yr:'Dec 2013 — Dec 2017',
    role:'Research Assistant',
    place:'Hanyang University · Ansan, South Korea',
    note:'geometry analysis lab · digital fabrication · Rhino3D / Grasshopper instruction',
  },
];

const EDUCATION = [
  { yr:'2018 — 2020', degree:'M.Sc. Integrative Technologies & Architectural Design Research', place:'Stuttgart University · Stuttgart, DE', note:'computational science · geometry · robotics · software component development' },
  { yr:'2010 — 2018', degree:'Bachelor of Architecture', place:'Hanyang University · Ansan, South Korea', note:'' },
];

const SERVICE = [
  { yr:'Nov 2011 — Nov 2013', degree:'Mandatory Military Service · Logistics', place:'MAKRI — Korean War Human Remains Recovery · Republic of Korea Army', note:'✦ 2012 Military Literature Awards — Honourable Mention, Poetry' },
];

function ExperienceContent(){
  return (
    <div style={{padding:'18px 22px'}}>
      <div className="slabel">003 — experience</div>
      <div style={{margin:'10px 0 14px'}} className="asub">From parametric design to AI engineering — Hamburg, Stuttgart, Seoul.</div>
      <div className="timeline">
        {EXPERIENCE.map((e,i) => (
          <div key={i} className="ev">
            <div className="yr">{e.yr}</div>
            <div className="role">{e.role}</div>
            <div className="place">{e.place}</div>
            {e.note && <div className="note">— {e.note}</div>}
          </div>
        ))}
      </div>
      <div className="slabel" style={{marginTop:22, marginBottom:10}}>education</div>
      <div className="timeline">
        {EDUCATION.map((e,i) => (
          <div key={i} className="ev">
            <div className="yr">{e.yr}</div>
            <div className="role">{e.degree}</div>
            <div className="place">{e.place}</div>
            {e.note && <div className="note">— {e.note}</div>}
          </div>
        ))}
      </div>
      <div className="slabel" style={{marginTop:22, marginBottom:10}}>service</div>
      <div className="timeline">
        {SERVICE.map((e,i) => (
          <div key={i} className="ev">
            <div className="yr">{e.yr}</div>
            <div className="role">{e.degree}</div>
            <div className="place">{e.place}</div>
            {e.note && <div className="note">{e.note}</div>}
          </div>
        ))}
      </div>
    </div>
  );
}

// ---------- WritingContent ----------
// Each post: yr, cat, title, excerpt, body (array of paragraphs — null = coming soon)
const POSTS = [
  {
    yr:'2026 · MAY', cat:'AGENTIC',
    title:'Why agentic systems still need humans (and what they do best)',
    excerpt:'A field-honest look at where the loop closes — and why "autonomous" doesn\'t mean "alone".',
    body: [
      'The conversation around agentic AI has a tendency to leap straight past the hard part — the moment when a chain of tool calls ends and someone has to decide whether the output is actually good.',
      'I\'ve spent the last year building and deploying agentic systems in enterprise contexts. The pattern I keep returning to: "autonomous" is a dial, not a switch. Most production systems sit somewhere around 70–80% autonomous. The last 20% — the edge cases, the ambiguous outputs, the decisions that carry real consequence — consistently end up back in human hands.',
      'That\'s not a failure state. It\'s the correct architecture.',
      'What works: design your agent to know what it doesn\'t know. Build an explicit escalation path. Treat human review not as a patch over uncertainty but as a first-class output of the system. The cost of a wrong autonomous decision is almost always higher than the cost of routing to a human.',
      'The teams that ship fastest are the ones who stopped trying to remove humans from the loop entirely, and started getting very precise about which part of the loop actually benefits from automation.',
    ],
  },
  {
    yr:'2026 · APR', cat:'RAG',
    title:'RAG evaluation, honestly — what we actually measure',
    excerpt:'A taxonomy of what people call "RAG eval", and what each metric tells you (or hides).',
    body: [
      '"How do we evaluate our RAG system?" is one of the most common questions I get. The honest answer is that it depends enormously on what you mean by "evaluate" — and most teams are conflating at least three different things.',
      'There\'s retrieval quality: did the right documents get retrieved? There\'s generation quality: did the model use them correctly? And there\'s downstream task quality: did the user get what they actually needed? Most off-the-shelf RAG eval pipelines measure one of these (usually generation, via LLM-as-judge) and stop there.',
      'This is better than nothing but it can mask serious retrieval failures that never surface in aggregate scores. The most useful thing I\'ve found: run metrics separately on retrieval and generation before combining them. A system with 60% retrieval recall and 90% generation faithfulness is a very different problem to debug than one with the numbers reversed.',
      'The other thing nobody talks about enough: eval sets go stale. The queries your users actually ask shift over time, and a set built from early beta traffic will miss the long-tail use cases that dominate production six months later. Budget time to refresh it.',
    ],
  },
  {
    yr:'2026 · MAR', cat:'PLATFORMS',
    title:'From PoC to platform — five things I wish I had done sooner',
    excerpt:'LLMOps notes from shipping a GenAI platform to 30+ enterprise teams.',
    body: null,
  },
  {
    yr:'2026 · FEB', cat:'TOOLS',
    title:'n8n for non-engineers — three recipes',
    excerpt:'Practical low-code workflows that punch above their weight.',
    body: null,
  },
  {
    yr:'2026 · JAN', cat:'NOTE',
    title:'On asking "why?" before "what?"',
    excerpt:'A short essay on value-led engineering, written between coffees.',
    body: null,
  },
];

function WritingContent({ api }){
  const [selected, setSelected] = React.useState(null);

  if (selected) {
    return (
      <React.Fragment>
        <div className="post-reader-header">
          <button className="back-btn" onClick={() => setSelected(null)}>← all posts</button>
          <span className="post-reader-tag">{selected.yr} · {selected.cat}</span>
        </div>
        <div className="post-reader">
          <h2 className="post-reader-title">{selected.title}</h2>
          {selected.body
            ? <div className="post-reader-body">
                {selected.body.map((para, i) => <p key={i}>{para}</p>)}
              </div>
            : <div className="post-reader-draft">— coming soon —</div>
          }
        </div>
      </React.Fragment>
    );
  }

  return (
    <React.Fragment>
      <div className="fmeta">
        <span>writing</span>
        <span className="count"><span className="n">{POSTS.length}</span> posts</span>
      </div>
      <div className="posts">
        {POSTS.map((p, i) => (
          <article key={i} className="post" onClick={() => setSelected(p)}>
            <div className="meta">{p.yr} · {p.cat}</div>
            <div className="ptitle">{p.title}</div>
            <div className="excerpt">{p.excerpt}</div>
            <div className="read-more">read →</div>
          </article>
        ))}
      </div>
    </React.Fragment>
  );
}

// ---------- PhotosContent ----------
// Simple synthesized landscape SVGs — duotone moss/terra, placeholder art
function svgAlps(){
  return (
    <svg viewBox="0 0 400 300" preserveAspectRatio="xMidYMid slice">
      <rect width="400" height="300" fill="#c8cfa8"/>
      <path d="M0 220 L80 110 L130 170 L200 80 L260 160 L320 100 L400 200 L400 300 L0 300 Z" fill="#3a4525"/>
      <path d="M0 240 L60 180 L110 220 L180 160 L240 210 L320 170 L400 240 L400 300 L0 300 Z" fill="#2c3520"/>
      <circle cx="320" cy="60" r="22" fill="#e9a682"/>
    </svg>
  );
}
function svgPorto(){
  return (
    <svg viewBox="0 0 400 300" preserveAspectRatio="xMidYMid slice">
      <rect width="400" height="300" fill="#e9a682"/>
      {Array.from({length:18}).map((_,i)=>(
        <rect key={i} x={i*22 + 6} y={140 + (i%3)*20} width="20" height={160-(i%3)*20} fill="#c0623a" stroke="#8a3f23" strokeWidth="0.8"/>
      ))}
      {Array.from({length:18}).map((_,i)=>(
        <polygon key={i+'r'} points={`${i*22+4},${140+(i%3)*20} ${i*22+16},${130+(i%3)*20} ${i*22+28},${140+(i%3)*20}`} fill="#8a3f23"/>
      ))}
      <rect width="400" height="80" fill="#3a4525" opacity="0.0"/>
    </svg>
  );
}
function svgHarz(){
  return (
    <svg viewBox="0 0 400 300" preserveAspectRatio="xMidYMid slice">
      <rect width="400" height="300" fill="#2c3520"/>
      {Array.from({length:24}).map((_,i)=>{
        const x = i*18 + (i%2)*9 - 10;
        const h = 160 + (i*7%80);
        const y = 300 - h;
        return <polygon key={i} points={`${x},${300} ${x+9},${y} ${x+18},${300}`} fill={i%3===0?'#a8b582':'#3a4525'}/>;
      })}
      <path d="M0 280 L400 280 L400 300 L0 300" fill="#1d1c1a"/>
    </svg>
  );
}
function svgJeju(){
  return (
    <svg viewBox="0 0 400 300" preserveAspectRatio="xMidYMid slice">
      <rect width="400" height="180" fill="#a8b582"/>
      <rect y="180" width="400" height="120" fill="#3a4525"/>
      <path d="M80 180 Q200 60 320 180 Z" fill="#1d1c1a"/>
      <path d="M170 180 Q200 140 230 180 Z" fill="#c0623a"/>
      <circle cx="60" cy="60" r="18" fill="#e9a682" opacity="0.85"/>
    </svg>
  );
}
function svgBerlin(){
  return (
    <svg viewBox="0 0 400 300" preserveAspectRatio="xMidYMid slice">
      <rect width="400" height="300" fill="#d8cda6"/>
      <rect y="200" width="400" height="100" fill="#7a7468"/>
      {Array.from({length:12}).map((_,i)=>(
        <rect key={i} x={i*34+4} y={120 - (i*13%80)} width="28" height={300 - (120 - (i*13%80))} fill="#3a4525"/>
      ))}
      <rect x="180" y="40" width="14" height="220" fill="#c0623a"/>
      <circle cx="187" cy="36" r="6" fill="#c0623a"/>
    </svg>
  );
}
function svgZurich(){
  return (
    <svg viewBox="0 0 400 300" preserveAspectRatio="xMidYMid slice">
      <rect width="400" height="300" fill="#c8cfa8"/>
      <path d="M0 130 L100 90 L180 120 L300 70 L400 110 L400 180 L0 180 Z" fill="#3a4525"/>
      <rect y="180" width="400" height="120" fill="#a8b582"/>
      <rect y="184" width="400" height="4" fill="#f1ead0" opacity="0.4"/>
      {Array.from({length:30}).map((_,i)=>(
        <rect key={i} x={i*14} y={210 + (i%2)*4} width="3" height="2" fill="#3a4525" opacity="0.5"/>
      ))}
    </svg>
  );
}

const PHOTOS = [
  { id:'alps',    tag:'alps',     yr:"aug '25", caption:'morning ridge', svg: svgAlps() },
  { id:'porto',   tag:'porto',    yr:"jun '25", caption:'old town roofs', svg: svgPorto() },
  { id:'harz',    tag:'harz',     yr:"oct '24", caption:'pine fog',       svg: svgHarz() },
  { id:'jeju',    tag:'jeju',     yr:"may '24", caption:'volcanic cone',  svg: svgJeju() },
  { id:'berlin',  tag:'berlin',   yr:"sep '23", caption:'fernsehturm',    svg: svgBerlin() },
  { id:'zurich',  tag:'zürich',   yr:"feb '26", caption:'lake on a clear day', svg: svgZurich() },
];

function PhotosContent({api}){
  return (
    <React.Fragment>
      <div className="fmeta">
        <span>travel · 6 places</span>
        <span className="count"><span className="n">{PHOTOS.length}</span> images</span>
      </div>
      <div className="photos">
        {PHOTOS.map(p => (
          <button key={p.id} className="ph" onClick={() => api && api.onPhotoClick && api.onPhotoClick(p)} aria-label={p.tag}>
            {p.svg}
            <span className="pyr">{p.yr}</span>
            <span className="ptag">{p.tag}</span>
          </button>
        ))}
      </div>
    </React.Fragment>
  );
}

// ---------- HobbiesContent ----------
const HOBBIES = [
  { name:'crochet',     meta:'mostly granny squares', line:'small steady satisfaction. ~30 squares this year.',
    ico:(
      <svg width="42" height="42" viewBox="0 0 42 42" fill="none" stroke="#1d1c1a" strokeWidth="1.4">
        <rect x="4" y="4" width="34" height="34"/>
        <rect x="10" y="10" width="22" height="22" stroke="#c0623a"/>
        <rect x="16" y="16" width="10" height="10" stroke="#a8b582"/>
        <circle cx="21" cy="21" r="2.5" fill="#c0623a" stroke="none"/>
      </svg>
    )},
  { name:'watercolour', meta:'landscape sketches', line:'on hikes. usually unfinished. that\'s the point.',
    ico:(
      <svg width="42" height="42" viewBox="0 0 42 42" fill="none" stroke="#1d1c1a" strokeWidth="1.4">
        <path d="M6 30 Q12 22 18 28 T30 26 T38 30" fill="#a8b582" stroke="none"/>
        <path d="M6 30 Q12 22 18 28 T30 26 T38 30"/>
        <circle cx="32" cy="10" r="3" fill="#c0623a" stroke="none"/>
        <rect x="6" y="34" width="32" height="2" fill="#1d1c1a"/>
      </svg>
    )},
  { name:'hiking',      meta:'alps · harz · jeju', line:'shorter routes, slower pace, longer coffees.',
    ico:(
      <svg width="42" height="42" viewBox="0 0 42 42" fill="none" stroke="#1d1c1a" strokeWidth="1.4">
        <path d="M3 34 L14 16 L22 26 L30 12 L40 34 Z" fill="#3a4525" stroke="#1d1c1a"/>
        <path d="M22 26 L26 22 L30 12" stroke="#f1ead0" strokeWidth="1"/>
        <circle cx="32" cy="8" r="2.5" fill="#e9a682" stroke="none"/>
      </svg>
    )},
  { name:'plants',      meta:'green thumb · 14 alive', line:'monstera +1 leaf this month. coriander attempt #4.',
    ico:(
      <svg width="42" height="42" viewBox="0 0 42 42" fill="none" stroke="#1d1c1a" strokeWidth="1.4">
        <path d="M21 26 Q12 16 8 6"/><ellipse cx="11" cy="11" rx="6" ry="2.5" fill="#3a4525" transform="rotate(-30 11 11)"/>
        <path d="M21 26 Q28 14 36 8"/><ellipse cx="34" cy="12" rx="6" ry="2.5" fill="#3a4525" transform="rotate(30 34 12)"/>
        <path d="M21 26 Q18 20 14 18"/><ellipse cx="15" cy="19" rx="4" ry="2" fill="#a8b582" transform="rotate(-10 15 19)"/>
        <path d="M14 28 L28 28 L26 38 L16 38 Z" fill="#c0623a"/>
      </svg>
    )},
];

function HobbiesContent(){
  const [growth, setGrowth] = React.useState(0);
  return (
    <React.Fragment>
      <div className="fmeta">
        <span>hobbies · off-screen me</span>
        <span className="count"><span className="n">{HOBBIES.length}</span> things</span>
      </div>
      <div className="hobbies-grid">
        {HOBBIES.map((h,i) => (
          <button key={h.name} className="hobby" onClick={() => h.name==='plants' && setGrowth(g=>g+1)} title={h.name==='plants' ? 'water the plant' : h.name}>
            <div className="h-ico" style={h.name==='plants' ? {transform:`scale(${1 + Math.min(growth,5)*0.06})`, transformOrigin:'bottom center', transition:'transform .25s'} : null}>
              {h.ico}
            </div>
            <div className="h-name">{h.name}</div>
            <div className="h-meta">{h.meta}{h.name==='plants' && growth>0 ? ` · +${growth} leaf${growth>1?'s':''}` : ''}</div>
            <div className="h-line">{h.line}</div>
          </button>
        ))}
      </div>
      <div style={{padding:'0 16px 14px', fontSize:'var(--t-xs)', letterSpacing:'var(--ls-cap)', textTransform:'uppercase', color:'var(--muted)'}}>
        tip — click the plant
      </div>
    </React.Fragment>
  );
}

// ---------- ContactContent ----------
function ContactContent(){
  return (
    <div className="contact">
      <div className="slabel" style={{marginBottom:14}}>say hello</div>
      <div className="row">
        <span className="k">email</span>
        <a className="v" href="mailto:jeongwoo.jang.k@gmail.com" contentEditable={false}>jeongwoo.jang.k@gmail.com</a>
      </div>
      <div className="row">
        <span className="k">linkedin</span>
        <a className="v" href="https://linkedin.com/in/jeongwoo-jang" contentEditable={false}>/in/jeongwoo-jang ↗</a>
      </div>
      <div className="row">
        <span className="k">github</span>
        <a className="v" href="https://github.com/Jeo-Jang" contentEditable={false}>@Jeo-Jang ↗</a>
      </div>
      <div className="row">
        <span className="k">located</span>
        <span className="v">Hamburg DE · Zürich CH</span>
      </div>
      <div className="row">
        <span className="k">status</span>
        <span className="v" style={{color:'var(--accent)', letterSpacing:'var(--ls-cap)', textTransform:'uppercase', fontSize:'var(--t-xs)'}}>● open — joining [company], aug '26</span>
      </div>
      <div style={{marginTop:18, fontSize:'var(--t-xs)', letterSpacing:'var(--ls-cap)', textTransform:'uppercase', color:'var(--muted)'}}>
        usually reply within 48h · prefer email
      </div>
    </div>
  );
}

// Expose all components to window for the resolver
Object.assign(window, {
  AboutContent,
  WorkContent,
  ExperienceContent,
  WritingContent,
  PhotosContent,
  HobbiesContent,
  ContactContent,
});
