/* global React */

// Hi-fi Portfolio — Minimal Modernist
// Components for the polished single-page site

const HeroAmbient = () => {
  // subtle drifting noise/blob field — SVG, low opacity, slow
  return (
    <svg className="hero-bg" viewBox="0 0 1440 900" preserveAspectRatio="xMidYMid slice">
      <defs>
        <radialGradient id="blob1" cx="50%" cy="50%" r="50%">
          <stop offset="0%" stopColor="oklch(0.58 0.21 25)" stopOpacity="0.18"/>
          <stop offset="100%" stopColor="oklch(0.58 0.21 25)" stopOpacity="0"/>
        </radialGradient>
        <radialGradient id="blob2" cx="50%" cy="50%" r="50%">
          <stop offset="0%" stopColor="oklch(0.5 0.18 250)" stopOpacity="0.16"/>
          <stop offset="100%" stopColor="oklch(0.5 0.18 250)" stopOpacity="0"/>
        </radialGradient>
        <filter id="grain">
          <feTurbulence type="fractalNoise" baseFrequency="0.85" numOctaves="2" seed="5"/>
          <feColorMatrix values="0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0.05 0"/>
        </filter>
      </defs>

      {/* slow drifting blobs */}
      <circle cx="200" cy="300" r="380" fill="url(#blob1)">
        <animate attributeName="cx" values="200;420;200" dur="32s" repeatCount="indefinite"/>
        <animate attributeName="cy" values="300;420;300" dur="38s" repeatCount="indefinite"/>
      </circle>
      <circle cx="1200" cy="600" r="420" fill="url(#blob2)">
        <animate attributeName="cx" values="1200;1000;1200" dur="40s" repeatCount="indefinite"/>
        <animate attributeName="cy" values="600;500;600" dur="34s" repeatCount="indefinite"/>
      </circle>

      {/* faint horizon line */}
      <line x1="0" y1="700" x2="1440" y2="700" stroke="var(--ink-line)" strokeWidth="1" opacity="0.4"/>

      {/* grain overlay */}
      <rect width="100%" height="100%" filter="url(#grain)"/>
    </svg>
  );
};

const Hero = () => (
  <section className="hero">
    <HeroAmbient/>
    <div className="hero-content">
      <div className="topbar">
        <div className="mono"><span className="dot"/>Open to junior full-stack roles · remote-friendly · 2026</div>
        <div className="mono">@SevenLawless — 101</div>
      </div>

      <div className="hero-name">
        <h1>
          Zakaria Zaoui,<br/>
          <em>junior full-stack developer.</em>
        </h1>
        <div className="hero-foot">
          <p className="hero-tagline">
            A small portfolio. A few projects. Honest notes on what I'm learning,
            and a <em>brain</em> to show you how it all connects.
          </p>
          <div className="hero-scroll">
            <a className="cv-link" href="resume.pdf" target="_blank" rel="noopener noreferrer">
              <span>view cv</span>
              <span>↗</span>
            </a>
            <span className="mono">scroll</span>
            <span className="arrow">↓</span>
          </div>
        </div>
      </div>
    </div>
  </section>
);

const About = () => (
  <section className="section" id="about">
    <div className="container">
      <div className="section-grid">
        <div className="section-rail">
          <div className="num">02</div>
          <div>about</div>
          <div className="meta">a paragraph, some facts</div>
        </div>
        <div>
          <h2 className="section-title">A short <em>introduction</em>.</h2>
          <div className="about-grid">
            <div className="bio">
              <p>
                I'm <em>Zakaria Zaoui</em> — a junior full-stack developer based in Morocco
                and open to remote work. I build practical web applications, backend APIs,
                automation tools, and database-backed systems using technologies like React,
                Node.js, Express, Python, SQL, and MySQL.
              </p>
              <p>
                I care about building software that solves real problems, not just looks
                good in screenshots. I like clean workflows, stable backends, clear data,
                simple interfaces, and products that are useful enough to become part of
                someone's daily routine — especially mine.
              </p>
              <p>
                Outside of code, I'm into gaming, 3D design, boxing, and hiking. I enjoy
                anything that mixes logic and creativity, especially when it helps me
                advance in life, learn faster, or build something more <em>useful</em> than
                a normal portfolio piece.
              </p>
            </div>

            <div className="facts">
              <dl>
                {[
                  ['Based in', 'Morocco · open to remote work'],
                  ['Stack',    'React · Vite · Node.js · Express · Python · SQL · MySQL'],
                  ['Status',   'Open to junior developer, Python, backend, full-stack, application support, technical support, freelance, and collaboration opportunities.'],
                  ['Outside',  'Gaming · 3D design · Boxing · Hiking'],
                  ['Years in', 'Since I can remember'],
                ].map(([k, v]) => (
                  <div className="row" key={k}>
                    <dt>{k}</dt>
                    <dd>{v}</dd>
                  </div>
                ))}
              </dl>
            </div>
          </div>
        </div>
      </div>
    </div>
  </section>
);

// ===== BRAIN =====

const PROJECTS = [
  {
    id: 1,
    title: 'ChioOS',
    tag: 'web app',
    side: 'L',
    desc: 'Private Life OS for expenses, workouts, jobs, documents, media, backups, and personal workflows.',
    tags: ['React', 'Vite', 'Node.js', 'Express', 'MySQL'],
    repo: 'https://github.com/SevenLawless/ChioOSVP'
  },
  {
    id: 2,
    title: 'Sheriff — Doc',
    tag: 'AI / OCR',
    side: 'L',
    desc: 'AI-assisted OCR pipeline for classifying and extracting data from scanned French and Arabic legal files.',
    tags: ['Python', 'OCR', 'NLP', 'SQL', 'APIs'],
    repo: 'https://github.com/SevenLawless/LegalDocClass'
  },
  {
    id: 3,
    title: 'Buggy',
    tag: 'support tool',
    side: 'L',
    desc: 'Bug-tracking dashboard for managing projects, issues, incidents, and resolution workflows.',
    tags: ['React', 'Node.js', 'Express', 'MySQL', 'REST APIs'],
    repo: 'https://github.com/SevenLawless/Buggy'
  },
  {
    id: 4,
    title: 'Poms AI',
    tag: 'creative AI',
    side: 'R',
    desc: 'Creative prompt-building tool for generating richer image prompts using style, mood, lighting, and composition.',
    tags: ['React', 'Vite', 'Prompt Engineering', 'UI Design', 'AI Workflows'],
    repo: 'https://github.com/SevenLawless/Poms_v2'
  },
  {
    id: 5,
    title: 'CaseForge AI',
    tag: 'developer tool',
    side: 'R',
    desc: 'Turns rough project notes into polished case studies, README sections, and resume bullets.',
    tags: ['React', 'Vite', 'JavaScript', 'LocalStorage', 'AI Workflows'],
    repo: 'https://github.com/SevenLawless/CaseForge-AI'
  }
];

// 1240 x 1380 viewBox — taller stage so cards don't collide at any width
const BRAIN = (() => {
  const W = 1240, H = 1380;
  const cx = W/2, cy = 680;
  const bw = 460, bh = 320;
  return { W, H, cx, cy, bw, bh };
})();

// Anatomical brain path — top-down view of cerebrum
const brainPathD = (() => {
  const { cx, cy, bw, bh } = BRAIN;
  return `
    M ${cx - bw*0.45} ${cy - bh*0.05}
    C ${cx - bw*0.55} ${cy - bh*0.32}, ${cx - bw*0.42} ${cy - bh*0.55}, ${cx - bw*0.28} ${cy - bh*0.55}
    C ${cx - bw*0.22} ${cy - bh*0.62}, ${cx - bw*0.08} ${cy - bh*0.6}, ${cx - bw*0.02} ${cy - bh*0.5}
    C ${cx + bw*0.02} ${cy - bh*0.62}, ${cx + bw*0.16} ${cy - bh*0.62}, ${cx + bw*0.22} ${cy - bh*0.55}
    C ${cx + bw*0.32} ${cy - bh*0.58}, ${cx + bw*0.5} ${cy - bh*0.36}, ${cx + bw*0.48} ${cy - bh*0.1}
    C ${cx + bw*0.55} ${cy + bh*0.18}, ${cx + bw*0.42} ${cy + bh*0.42}, ${cx + bw*0.28} ${cy + bh*0.46}
    C ${cx + bw*0.18} ${cy + bh*0.58}, ${cx + bw*0.06} ${cy + bh*0.55}, ${cx} ${cy + bh*0.5}
    C ${cx - bw*0.06} ${cy + bh*0.55}, ${cx - bw*0.18} ${cy + bh*0.58}, ${cx - bw*0.28} ${cy + bh*0.46}
    C ${cx - bw*0.42} ${cy + bh*0.42}, ${cx - bw*0.55} ${cy + bh*0.18}, ${cx - bw*0.45} ${cy - bh*0.05}
    Z
  `;
})();

// anchor points (where wires meet brain edge) per project
const anchors = {
  1: { x: BRAIN.cx - BRAIN.bw*0.5,  y: BRAIN.cy - BRAIN.bh*0.45 },
  2: { x: BRAIN.cx - BRAIN.bw*0.55, y: BRAIN.cy + BRAIN.bh*0.0 },
  3: { x: BRAIN.cx - BRAIN.bw*0.42, y: BRAIN.cy + BRAIN.bh*0.45 },
  4: { x: BRAIN.cx + BRAIN.bw*0.5,  y: BRAIN.cy - BRAIN.bh*0.4 },
  5: { x: BRAIN.cx + BRAIN.bw*0.48, y: BRAIN.cy + BRAIN.bh*0.4 },
};

// card positions (top-left x/y in viewBox space) — spaced ~470px apart for 348px-tall cards
const cardLayout = {
  1: { x: 20,    y: 30   },
  2: { x: 0,     y: 510  },
  3: { x: 30,    y: 990  },
  4: { x: 956,   y: 80   },
  5: { x: 956,   y: 920  },
};

const Brain = ({ activeId, setActiveId }) => {
  const { W, H, cx, cy, bw, bh } = BRAIN;
  const stageRef = React.useRef(null);

  // wire color per side
  const wireColor = (side) => side === 'L' ? 'var(--red)' : 'var(--blue)';

  return (
    <div className="brain-stage" ref={stageRef}>
      <svg className="brain-svg" viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="xMidYMid meet">
        <defs>
          <clipPath id="brain-clip">
            <path d={brainPathD}/>
          </clipPath>
        </defs>

        {/* hemisphere tints */}
        <g clipPath="url(#brain-clip)">
          <rect x="0" y="0" width={cx} height={H} fill="var(--red)" opacity="0.07"/>
          <rect x={cx} y="0" width={cx} height={H} fill="var(--blue)" opacity="0.07"/>
        </g>

        {/* connection wires (drawn before card surfaces, after brain tint) */}
        {PROJECTS.map(p => {
          const a = anchors[p.id];
          const c = cardLayout[p.id];
          const cardX = p.side === 'L' ? c.x + 264 : c.x;
          const cardY = c.y + 60;
          const isLeft = p.side === 'L';
          const dx = cardX - a.x;
          const c1x = a.x + dx * 0.25;
          const c1y = a.y;
          const c2x = a.x + dx * 0.75;
          const c2y = cardY;
          const isActive = activeId === p.id;
          return (
            <g key={p.id} className="wire">
              <path
                d={`M ${a.x} ${a.y} C ${c1x} ${c1y}, ${c2x} ${c2y}, ${cardX} ${cardY}`}
                fill="none"
                stroke={wireColor(p.side)}
                strokeWidth={isActive ? 2 : 1}
                opacity={isActive ? 1 : 0.55}
                strokeLinecap="round"
                style={{ transition: 'all .35s ease' }}
              />
              {/* anchor dot on brain */}
              <circle cx={a.x} cy={a.y} r={isActive ? 6 : 4}
                      fill="var(--paper)"
                      stroke={wireColor(p.side)}
                      strokeWidth={isActive ? 2.5 : 1.5}
                      style={{ transition: 'all .3s ease' }}/>
              {/* card-side dot */}
              <circle cx={cardX} cy={cardY} r="3.5"
                      fill={wireColor(p.side)}
                      opacity={isActive ? 1 : 0.7}/>
              {/* gentle pulse along wire when active */}
              {isActive && (
                <circle r="4" fill={wireColor(p.side)}>
                  <animateMotion dur="1.6s" repeatCount="indefinite"
                                 path={`M ${a.x} ${a.y} C ${c1x} ${c1y}, ${c2x} ${c2y}, ${cardX} ${cardY}`}/>
                </circle>
              )}
            </g>
          );
        })}

        {/* brain outline */}
        <path d={brainPathD} fill="none" stroke="var(--ink)" strokeWidth="1.5"/>

        {/* longitudinal fissure */}
        <path
          d={`M ${cx} ${cy - bh*0.5}
              C ${cx + 6} ${cy - bh*0.25}, ${cx - 4} ${cy - bh*0.05}, ${cx + 2} ${cy + bh*0.1}
              C ${cx - 4} ${cy + bh*0.3}, ${cx + 5} ${cy + bh*0.42}, ${cx} ${cy + bh*0.5}`}
          fill="none" stroke="var(--ink)" strokeWidth="1.2"/>

        {/* sulci — left, organic */}
        <g stroke="var(--red)" strokeWidth="1" fill="none" opacity="0.55" strokeLinecap="round">
          <path d={`M ${cx - 200} ${cy - 90} Q ${cx - 150} ${cy - 110}, ${cx - 90} ${cy - 95} Q ${cx - 60} ${cy - 80}, ${cx - 40} ${cy - 95}`}/>
          <path d={`M ${cx - 220} ${cy - 30} Q ${cx - 160} ${cy - 50}, ${cx - 100} ${cy - 35} Q ${cx - 60} ${cy - 25}, ${cx - 30} ${cy - 40}`}/>
          <path d={`M ${cx - 210} ${cy + 30} Q ${cx - 140} ${cy + 10}, ${cx - 80} ${cy + 30} Q ${cx - 50} ${cy + 50}, ${cx - 30} ${cy + 25}`}/>
          <path d={`M ${cx - 180} ${cy + 90} Q ${cx - 120} ${cy + 70}, ${cx - 70} ${cy + 95} Q ${cx - 50} ${cy + 110}, ${cx - 30} ${cy + 95}`}/>
          <path d={`M ${cx - 100} ${cy - 130} Q ${cx - 70} ${cy - 145}, ${cx - 30} ${cy - 130}`}/>
        </g>
        {/* sulci — right */}
        <g stroke="var(--blue)" strokeWidth="1" fill="none" opacity="0.55" strokeLinecap="round">
          <path d={`M ${cx + 40} ${cy - 95} Q ${cx + 60} ${cy - 80}, ${cx + 90} ${cy - 95} Q ${cx + 150} ${cy - 110}, ${cx + 200} ${cy - 90}`}/>
          <path d={`M ${cx + 30} ${cy - 40} Q ${cx + 60} ${cy - 25}, ${cx + 100} ${cy - 35} Q ${cx + 160} ${cy - 50}, ${cx + 220} ${cy - 30}`}/>
          <path d={`M ${cx + 30} ${cy + 25} Q ${cx + 50} ${cy + 50}, ${cx + 80} ${cy + 30} Q ${cx + 140} ${cy + 10}, ${cx + 210} ${cy + 30}`}/>
          <path d={`M ${cx + 30} ${cy + 95} Q ${cx + 50} ${cy + 110}, ${cx + 70} ${cy + 95} Q ${cx + 120} ${cy + 70}, ${cx + 180} ${cy + 90}`}/>
          <path d={`M ${cx + 30} ${cy - 130} Q ${cx + 70} ${cy - 145}, ${cx + 100} ${cy - 130}`}/>
        </g>

        {/* cerebellum hint at bottom */}
        <path d={`M ${cx - 100} ${cy + bh*0.5}
                 Q ${cx} ${cy + bh*0.6}, ${cx + 100} ${cy + bh*0.5}`}
              fill="none" stroke="var(--ink)" strokeWidth="1" opacity="0.5"/>

        {/* hemisphere labels */}
        <g fontFamily="JetBrains Mono, monospace" fontSize="10" letterSpacing="0.18em">
          <text x={cx - bw*0.5} y={cy - bh*0.62} fill="var(--red)">L · LOGIC</text>
          <text x={cx - bw*0.5} y={cy - bh*0.62 + 14} fill="var(--ink-faint)" fontSize="9" letterSpacing="0.05em">structure · systems</text>
          <text x={cx + bw*0.32} y={cy - bh*0.62} fill="var(--blue)">R · CRAFT</text>
          <text x={cx + bw*0.32} y={cy - bh*0.62 + 14} fill="var(--ink-faint)" fontSize="9" letterSpacing="0.05em">curiosity · feel</text>
        </g>

        {/* tiny scale marks at bottom */}
        <g fontFamily="JetBrains Mono, monospace" fontSize="9" fill="var(--ink-faint)" letterSpacing="0.1em">
          <text x={cx - 60} y={cy + bh*0.66}>fig.01 · projects.brain — 5 nodes shown</text>
        </g>
      </svg>

      {/* CARDS */}
      {PROJECTS.map(p => {
        const c = cardLayout[p.id];
        return (
          <ProjectCard
            key={p.id}
            project={p}
            xPct={(c.x / BRAIN.W) * 100}
            yPct={(c.y / BRAIN.H) * 100}
            wPct={(264 / BRAIN.W) * 100}
            hovered={activeId === p.id}
            onEnter={() => setActiveId(p.id)}
            onLeave={() => setActiveId(null)}
          />
        );
      })}
    </div>
  );
};

const ProjectThumb = ({ id }) => (
  <img
    src={`uploads/p${id}.png`}
    alt={`Project ${id} screenshot`}
    style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }}
  />
);

const ProjectCard = ({ project, xPct, yPct, wPct, hovered, onEnter, onLeave }) => (
  <article
    className="project-card"
    style={{
      left: `${xPct}%`, top: `${yPct}%`, width: `${wPct}%`,
      borderColor: hovered ? (project.side === 'L' ? 'var(--red)' : 'var(--blue)') : undefined
    }}
    onMouseEnter={onEnter}
    onMouseLeave={onLeave}
  >
    <header className="pc-head">
      <span>0{project.id} / 05</span>
      <span className={project.side === 'L' ? 'side-l' : 'side-r'}>
        {project.side} · {project.tag}
      </span>
    </header>
    <div className="pc-thumb">
      <ProjectThumb id={project.id}/>
    </div>
    <h3 className="pc-title">{project.title}</h3>
    <p className="pc-desc">{project.desc}</p>
    <div className="pc-tags">
      {project.tags.map((t, i) => (
        <React.Fragment key={t}>
          <span>{t}</span>
          {i < project.tags.length - 1 && <span className="pc-tag-sep">·</span>}
        </React.Fragment>
      ))}
    </div>
    <a className="pc-foot" href={project.repo} target="_blank" rel="noopener noreferrer">
      <span>view on github</span>
      <span className="arrow">→</span>
    </a>
  </article>
);

const Projects = () => {
  const [activeId, setActiveId] = React.useState(null);
  return (
    <section className="section brain-section" id="projects">
      <div className="container">
        <div className="section-grid">
          <div className="section-rail">
            <div className="num">03</div>
            <div>projects</div>
            <div className="meta">five threads</div>
          </div>
          <div>
            <h2 className="section-title">
              <span style={{ color: 'var(--red)' }}>Half logic.</span> <em style={{ color: 'var(--blue)' }}>Half feels.</em>
            </h2>
            <p className="section-lede">
              Five projects, sketched as connections from one mind. Hover any thread to follow the wire.
            </p>
            <Brain activeId={activeId} setActiveId={setActiveId}/>
          </div>
        </div>
      </div>
    </section>
  );
};

// ===== SKILLS =====
const SKILL_GROUPS = [
  { label: 'Frontend', items: [
    ['HTML', 5], ['CSS', 5], ['JavaScript', 5], ['React', 4], ['Vite', 4], ['TypeScript', 4]
  ]},
  { label: 'Backend',  items: [
    ['Node.js', 5], ['REST APIs', 5], ['Python', 5], ['SQL', 5], ['MySQL', 5], ['Django', 5]
  ]},
  { label: 'Tools',    items: [
    ['Git / GitHub', 5], ['VS Code', 5], ['Docker', 5], ['VPS hosting', 5], ['Linux / SSH', 5], ['MySQL Workbench', 5], ['Tailscale', 5]
  ]},
  { label: 'Learning', learning: true, items: [
    ['Max security VPS', 'learning'], ['Linux server & SSH', 'learning'], ['3D Design', 'learning'], ['Python & SQL depth', 'learning'], ['Data science / ML', 'learning'], ['3D Animation', 'soon']
  ]},
];

const Skills = () => (
  <section className="section" id="skills">
    <div className="container">
      <div className="section-grid">
        <div className="section-rail">
          <div className="num">04</div>
          <div>skills</div>
          <div className="meta">tools, honestly rated</div>
        </div>
        <div>
          <h2 className="section-title">What I <em>work</em> with.</h2>
          <p className="section-lede">
            Dots are confidence, not years. <em>wip</em> means I'm still learning out loud.
          </p>
          <div className="skills-grid">
            {SKILL_GROUPS.map(g => (
              <div className={`skill-group ${g.learning ? 'learning' : ''}`} key={g.label}>
                <h3>
                  <span>{g.label}</span>
                  <span className="count">{g.items.length}</span>
                </h3>
                <ul>
                  {g.items.map(([name, level]) => (
                    <li key={name}>
                      <span>{name}</span>
                      {typeof level === 'number' ? (
                        <span className="level">
                          {[...Array(5)].map((_, i) => (
                            <span key={i} className={`pip ${i < level ? '' : 'off'}`}/>
                          ))}
                        </span>
                      ) : (
                        <span className="level">{level}</span>
                      )}
                    </li>
                  ))}
                </ul>
              </div>
            ))}
          </div>
        </div>
      </div>
    </div>
  </section>
);

// ===== JOURNEY =====
const STOPS = [
  { year: '2022', title: 'Specialized Studies',  detail: 'Full-stack development and project management fundamentals.' },
  { year: '2024', title: "Bachelor's Degree",    detail: 'Applied Computer Science at Mundiapolis University — thesis on AI integration in commerce.' },
  { year: '2025', title: 'Full-Stack Developer', detail: 'Built and maintained client websites, backend API features, and database apps at Creativity E-Marketing.' },
  { year: '2025', title: 'Robotics Trainer',     detail: 'Taught robotics, electronics, sensors, and beginner programming at Coin Etudiant.' },
  { year: '2026', title: 'Building ChioOS',      detail: 'Building a private full-stack Life OS while improving Docker, VPS, Linux, SSH, and project architecture.', state: 'now' },
  { year: '2026', title: 'Junior dev role',      detail: 'Targeting junior full-stack, backend, application support, technical support, freelance, and collaboration.', state: 'next' },
];

const Journey = () => (
  <section className="section" id="journey">
    <div className="container">
      <div className="section-grid">
        <div className="section-rail">
          <div className="num">05</div>
          <div>journey</div>
          <div className="meta">career &amp; milestones</div>
        </div>
        <div>
          <h2 className="section-title">A timeline of <em>milestones</em>.</h2>
          <p className="section-lede">
            From specialized studies to real products, one step at a time.
          </p>

          <div className="journey">

            <div className="journey-grid">
              {STOPS.map((s, i) => (
                <div key={i} className={`journey-stop ${s.state || ''}`}>
                  <div className="year">{s.year}</div>
                  <div className="dot"/>
                  <h4>{s.title}</h4>
                  <p>{s.detail}</p>
                </div>
              ))}
            </div>
          </div>
        </div>
      </div>
    </div>
  </section>
);

const Contact = () => (
  <section className="contact" id="contact">
    <div className="container">
      <div className="section-grid">
        <div className="section-rail">
          <div className="num">06</div>
          <div>contact</div>
          <div className="meta">say hi</div>
        </div>
        <div>
          <h2 className="section-title" style={{ maxWidth: 760 }}>
            If you'd like to <em>talk</em>, I'd like to listen.
          </h2>
          <p className="section-lede">
            Job leads, project ideas, book recs, weird questions — all welcome.
          </p>
          <a className="contact-mail" href="mailto:7lawless25@gmail.com">
            7lawless25<span className="at">@</span>gmail.com
          </a>

          <div className="socials">
            <a href="https://github.com/SevenLawless"><span className="label">GitHub</span> @SevenLawless</a>
            <a href="https://www.linkedin.com/in/zakaria-zaoui-9a7836334/"><span className="label">LinkedIn</span> /in/zakaria-zaoui-9a7836334</a>
            <a href="resume.pdf" target="_blank" rel="noopener noreferrer"><span className="label">CV</span> Download résumé ↓</a>
          </div>

          <div className="footer">
            <span>made by hand · Zakaria Zaoui · 2026 · v0.1.0</span>
            <a href="#top">↑ back to top</a>
          </div>
        </div>
      </div>
    </div>
  </section>
);

window.PortfolioApp = { Hero, About, Projects, Skills, Journey, Contact };
