// ═══════════════════════════════════════════════════════════════════════
// Portfolio — multimedia designer
// ═══════════════════════════════════════════════════════════════════════

function embedUrl(url) {
  if (!url) return null;
  let m = url.match(/youtube\.com\/watch\?v=([^&]+)/);
  if (m) return `https://www.youtube.com/embed/${m[1]}`;
  m = url.match(/youtu\.be\/([^?]+)/);
  if (m) return `https://www.youtube.com/embed/${m[1]}`;
  m = url.match(/youtube\.com\/embed\/([^?]+)/);
  if (m) return url;
  m = url.match(/vimeo\.com\/(\d+)/);
  if (m) return `https://player.vimeo.com/video/${m[1]}`;
  return url;
}

// ─── L — shorthand for editable label strings in `data.labels` ─────────
// Visitors see plain text; admins click to edit. Use anywhere a hardcoded
// string used to live.
function L({ k }) {
  return <EText section="labels" sub={k} />;
}

// ─── SectionHead — fully editable section header ───────────────────────
// `num` is the bracketed counter (e.g. "[ 01 · about ]").
// Title is 3 fields (pre, accent, suf) so the colored highlight is its
// own clickable target in admin mode.
function SectionHead({ id, numKey, prePart, accentPart, sufPart, aside1Key, aside2Key }) {
  return (
    <div className="sect-head reveal">
      <div className="sect-num">
        <L k={numKey} />
      </div>
      <h2 className="sect-title">
        <L k={prePart} />
        <em><L k={accentPart} /></em>
        <L k={sufPart} />
      </h2>
      <div className="sect-aside">
        <b><L k={aside1Key} /></b><br />
        <L k={aside2Key} />
      </div>
    </div>
  );
}

function useScrollClass() {
  const [s, setS] = React.useState(false);
  React.useEffect(() => {
    const fn = () => setS(window.scrollY > 24);
    fn();
    window.addEventListener("scroll", fn, { passive: true });
    return () => window.removeEventListener("scroll", fn);
  }, []);
  return s;
}

// ─── Nav ────────────────────────────────────────────────────────────────

function Nav({ isAdmin, onLockClick, signature }) {
  const scrolled = useScrollClass();
  return (
    <nav className={scrolled ? "nav scrolled" : "nav"}>
      <a className="nav-brand" href="#top">
        <span className="glyph"><BrandGlyph letter={(signature || "A")[0]} /></span>
        <span className="at">@</span>
        <span className="name">
          <EText section="signature" />
        </span>
        <span className="slash">/</span>
        <span className="at"><L k="brandTagline" /></span>
      </a>
      <div className="nav-links">
        <a href="#about"><span className="nm">01</span><L k="navAbout" /></a>
        <a href="#skills"><span className="nm">02</span><L k="navSkills" /></a>
        <a href="#reel"><span className="nm">03</span><L k="navReel" /></a>
        <a href="#certs"><span className="nm">04</span><L k="navCerts" /></a>
        <a href="#cv"><span className="nm">05</span><L k="navCv" /></a>
        <a href="#contact"><span className="nm">06</span><L k="navContact" /></a>
      </div>
      <div className="nav-right">
        <span className="nav-time"><LiveClock tz="Africa/Cairo" /> CAI</span>
        <button className={`nav-lock ${isAdmin ? "admin" : ""}`}
                onClick={onLockClick}
                title={isAdmin ? "Admin mode" : "Studio access"}>
          {isAdmin ? (
            <svg width="14" height="14" viewBox="0 0 14 14" fill="currentColor"><path d="M4 6V4a3 3 0 0 1 6 0v2h1v7H3V6h1zm1 0h4V4a2 2 0 0 0-4 0v2z" /></svg>
          ) : (
            <svg width="14" height="14" viewBox="0 0 14 14" fill="currentColor"><path d="M4 6V4a3 3 0 0 1 6 0h-1a2 2 0 0 0-4 0v2h6v7H3V6h1z" /></svg>
          )}
        </button>
      </div>
    </nav>
  );
}

// ─── Hero ───────────────────────────────────────────────────────────────

function Hero() {
  const { data } = React.useContext(AdminCtx);
  return (
    <section className="hero" id="top">
      <div className="hero-mark" aria-hidden="true">26</div>
      <div className="hero-top reveal">
        <div>
          <div className="hero-eyebrow">
            <span className="bracket">[</span>
            <span className="led" />
            <EText section="hero" sub="eyebrow" />
            <span className="bracket">]</span>
          </div>
        </div>
        <div className="hero-counter">
          <span><L k="heroRefLabel" /> · <b><L k="heroRefValue" /></b></span>
          <span><L k="heroSessionLabel" /> · <b><FrameCounter value={1247} /></b></span>
        </div>
      </div>

      <div className="reveal" style={{ animationDelay: "100ms" }}>
        <h1 className="hero-name">
          <span className="first"><EText section="hero" sub="firstName" /></span>
          <span className="last"><EText section="hero" sub="lastName" /></span>
        </h1>
        <p className="hero-title">
          <EText section="hero" sub="title" multiline />
        </p>
      </div>

      <div className="hero-bottom reveal" style={{ animationDelay: "250ms" }}>
        <div className="hero-stats">
          <div className="hero-stat">
            <div className="k"><L k="heroStatYearsLbl" /></div>
            <div className="v"><span className="acc"><EText section="hero" sub="yearsExp" /></span> <L k="heroStatYearsUnit" /></div>
          </div>
          <div className="hero-stat">
            <div className="k"><L k="heroStatDeliverablesLbl" /></div>
            <div className="v"><span className="acc"><EText section="hero" sub="deliverables" /></span> <L k="heroStatDeliverablesUnit" /></div>
          </div>
          <div className="hero-stat">
            <div className="k"><L k="heroStatStudiosLbl" /></div>
            <div className="v"><span className="acc"><EText section="hero" sub="studios" /></span> <L k="heroStatStudiosUnit" /></div>
          </div>
          <div className="hero-stat">
            <div className="k"><L k="heroStatStatusLbl" /></div>
            <div className="v"><span className="acc">●</span> <EText section="hero" sub="available" /></div>
          </div>
          <div className="hero-stat">
            <div className="k"><L k="heroStatLocationLbl" /></div>
            <div className="v"><EText section="hero" sub="location" /></div>
          </div>
          <div className="hero-stat">
            <div className="k"><L k="heroStatRoleLbl" /></div>
            <div className="v"><EText section="hero" sub="role" /></div>
          </div>
        </div>
        <div>
          <div className="mono" style={{ marginBottom: 14 }}><L k="heroDisciplinesLbl" /></div>
          <div className="hero-disciplines">
            <EList
              section="disciplines"
              template={() => "New discipline"}
              label="discipline"
              renderItem={(_, i) => (
                <DisciplineTag>
                  <EText section="disciplines" sub={i} />
                </DisciplineTag>
              )}
            />
          </div>
        </div>
      </div>
    </section>
  );
}

// ─── Marquee bar ────────────────────────────────────────────────────────

function MarqueeBar() {
  const { isAdmin, data, update } = React.useContext(AdminCtx);
  const items = data.marquee || [];

  if (isAdmin) {
    // In admin mode the animation pauses and each item becomes editable.
    // Visitors see the live scrolling version.
    const removeItem = (i) => update("marquee", items.filter((_, j) => j !== i));
    const addItem = () => update("marquee", [...items, "New ticker item"]);
    const move = (i, dir) => {
      const j = i + dir;
      if (j < 0 || j >= items.length) return;
      const next = items.slice();
      [next[i], next[j]] = [next[j], next[i]];
      update("marquee", next);
    };

    return (
      <div className="marquee marquee-admin">
        <div className="marquee-admin-label">// Ticker · click any item to edit</div>
        <div className="marquee-admin-track">
          {items.map((it, i) => (
            <span key={i} className="marquee-item marquee-item-admin">
              <EText section="marquee" sub={i} />
              <span className="ma-actions" data-noncommentable>
                <button onClick={() => move(i, -1)} disabled={i === 0} title="Move left">‹</button>
                <button onClick={() => move(i, 1)} disabled={i === items.length - 1} title="Move right">›</button>
                <button className="danger" onClick={() => removeItem(i)} title="Remove">✕</button>
              </span>
              <span className="sep">●</span>
            </span>
          ))}
          <button className="marquee-add" onClick={addItem}>+ Add item</button>
        </div>
      </div>
    );
  }

  return <Marquee items={items} />;
}

// ─── About ──────────────────────────────────────────────────────────────

function AboutSection() {
  const { isAdmin } = React.useContext(AdminCtx);
  return (
    <section id="about">
      <SectionHead
        numKey="aboutNum"
        prePart="aboutTitlePre"
        accentPart="aboutTitleAccent"
        sufPart="aboutTitleSuf"
        aside1Key="aboutAside1"
        aside2Key="aboutAside2"
      />
      <div className="about">
        <div className="about-portrait reveal">
          <EImage section="about" sub="portrait" placeholderText="// Drop in a portrait or studio shot //" />
          <div className="corner tl" />
          <div className="corner tr" />
          <div className="corner bl" />
          <div className="corner br" />
          <div className="label"><EText section="about" sub="portraitLabel" /></div>
        </div>
        <div className="reveal" style={{ animationDelay: "100ms" }}>
          <div className="about-body">
            <EList
              section="about"
              sub="paragraphs"
              template={() => "A new paragraph. Click to edit."}
              label="paragraph"
              renderItem={(_, i) => (
                <p><EText section="about" sub={["paragraphs", i]} multiline /></p>
              )}
            />
          </div>
          <div className="about-readout">
            <EList
              section="about"
              sub="readout"
              template={() => ({ k: "Label", v: "Value", acc: false })}
              label="row"
              renderItem={(row, i) => (
                <div className="row" style={{ gridColumn: "span 1" }}>
                  <span className="k">
                    <EText section="about" sub={["readout", i, "k"]} />
                  </span>
                  <span className={row.acc ? "v acc" : "v"}>
                    {row.acc && <span style={{ marginRight: 6 }}>●</span>}
                    <EText section="about" sub={["readout", i, "v"]} />
                  </span>
                </div>
              )}
            />
          </div>
        </div>
      </div>
    </section>
  );
}

// ─── Skills ─────────────────────────────────────────────────────────────

function SkillsSection() {
  const { isAdmin, data, update } = React.useContext(AdminCtx);
  const skills = data.skills || [];

  const updateSkillLevel = (catIdx, itemIdx, level) => {
    const next = skills.map((c, i) => {
      if (i !== catIdx) return c;
      return {
        ...c,
        items: c.items.map((it, j) => (j === itemIdx ? { ...it, level } : it)),
      };
    });
    update("skills", next);
  };

  const addItem = (catIdx) => {
    const next = skills.map((c, i) =>
      i !== catIdx ? c : { ...c, items: [...c.items, { name: "NEW SKILL", level: 0.7 }] }
    );
    update("skills", next);
  };

  const removeItem = (catIdx, itemIdx) => {
    const next = skills.map((c, i) =>
      i !== catIdx ? c : { ...c, items: c.items.filter((_, j) => j !== itemIdx) }
    );
    update("skills", next);
  };

  const addCategory = () => {
    update("skills", [...skills, { name: "New Category", items: [{ name: "Skill", level: 0.7 }] }]);
  };

  const removeCategory = (catIdx) => {
    update("skills", skills.filter((_, i) => i !== catIdx));
  };

  return (
    <section id="skills">
      <SectionHead
        numKey="skillsNum"
        prePart="skillsTitlePre"
        accentPart="skillsTitleAccent"
        sufPart="skillsTitleSuf"
        aside1Key="skillsAside1"
        aside2Key="skillsAside2"
      />
      <div className="skills-stack reveal">
        {skills.map((cat, ci) => (
          <div key={ci} className="skill-cat">
            <div className="skill-cat-head">
              <span className="skill-cat-num">[ 0{ci + 1} ]</span>
              <span className="skill-cat-name">
                <EText section="skills" sub={[ci, "name"]} />
              </span>
              {isAdmin && (
                <button
                  className="btn-mini danger"
                  style={{ marginLeft: "auto", padding: "4px 8px", fontSize: 10 }}
                  onClick={() => removeCategory(ci)}
                  title="Remove category"
                >✕</button>
              )}
            </div>
            <ul className="skill-list">
              {cat.items.map((item, ii) => (
                <li key={ii} className="skill-item" style={{ position: "relative" }}>
                  <span className="name">
                    <EText section="skills" sub={[ci, "items", ii, "name"]} />
                  </span>
                  <span
                    onClick={(e) => {
                      if (!isAdmin) return;
                      const rect = e.currentTarget.getBoundingClientRect();
                      const lvl = Math.max(0.05, Math.min(1, (e.clientX - rect.left) / rect.width));
                      updateSkillLevel(ci, ii, lvl);
                    }}
                    style={{ cursor: isAdmin ? "ew-resize" : "default", display: "inline-block" }}
                    title={isAdmin ? "Click to set proficiency" : undefined}
                  >
                    <SkillMeter level={item.level} />
                  </span>
                  {isAdmin && (
                    <button
                      onClick={() => removeItem(ci, ii)}
                      style={{
                        position: "absolute",
                        right: -28, top: 0,
                        background: "transparent",
                        border: 0,
                        color: "var(--red)",
                        cursor: "pointer",
                        opacity: 0.5,
                        fontSize: 14,
                      }}
                      title="Remove skill"
                    >✕</button>
                  )}
                </li>
              ))}
            </ul>
            {isAdmin && (
              <button
                className="elist-add"
                style={{ marginTop: 16, fontSize: 12, padding: "6px 12px", color: "var(--accent)", borderColor: "var(--accent)" }}
                onClick={() => addItem(ci)}
              >+ Add skill</button>
            )}
          </div>
        ))}
      </div>
      {isAdmin && (
        <button
          className="elist-add"
          style={{ marginTop: 20, color: "var(--accent)", borderColor: "var(--accent)" }}
          onClick={addCategory}
        >+ Add category</button>
      )}
    </section>
  );
}

// ─── Videos / Reel ──────────────────────────────────────────────────────

// ─── Lightbox — fullscreen image/video preview ──────────────────────────

function Lightbox({ items, index, onClose, onNavigate }) {
  const total = items.length;
  const goPrev = React.useCallback(() => onNavigate((index - 1 + total) % total), [index, total, onNavigate]);
  const goNext = React.useCallback(() => onNavigate((index + 1) % total), [index, total, onNavigate]);

  React.useEffect(() => {
    const onKey = (e) => {
      if (e.key === "Escape") onClose();
      else if (e.key === "ArrowLeft" && total > 1) goPrev();
      else if (e.key === "ArrowRight" && total > 1) goNext();
    };
    window.addEventListener("keydown", onKey);
    document.body.style.overflow = "hidden";
    return () => {
      window.removeEventListener("keydown", onKey);
      document.body.style.overflow = "";
    };
  }, [onClose, goPrev, goNext, total]);

  // Mouse-drag / trackpad swipe support on the media area.
  const dragRef = React.useRef(null);
  const onMediaMouseDown = (e) => {
    e.stopPropagation();
    dragRef.current = { x: e.clientX, moved: false };
  };
  const onMediaMouseMove = (e) => {
    if (!dragRef.current) return;
    if (Math.abs(e.clientX - dragRef.current.x) > 8) dragRef.current.moved = true;
  };
  const onMediaMouseUp = (e) => {
    if (!dragRef.current) return;
    const dx = e.clientX - dragRef.current.x;
    dragRef.current = null;
    if (total > 1 && Math.abs(dx) > 60) {
      if (dx > 0) goPrev(); else goNext();
    }
  };

  const item = items[index];
  if (!item) return null;
  const { url, title, year, description, isImage } = item;
  const src = isImage ? null : embedUrl(url);
  const isEmbed = src && /(youtube|vimeo|youtu\.be)/.test(url);

  return (
    <div className="lightbox" onClick={onClose}>
      <button className="lb-close" onClick={onClose} title="Close (Esc)">✕</button>
      {total > 1 && (
        <>
          <button className="lb-nav lb-prev" onClick={(e) => { e.stopPropagation(); goPrev(); }} title="Previous (←)">‹</button>
          <button className="lb-nav lb-next" onClick={(e) => { e.stopPropagation(); goNext(); }} title="Next (→)">›</button>
        </>
      )}
      <div
        className="lb-media"
        onClick={(e) => e.stopPropagation()}
        onMouseDown={onMediaMouseDown}
        onMouseMove={onMediaMouseMove}
        onMouseUp={onMediaMouseUp}
      >
        {isImage && <img src={url} alt={title || ""} draggable={false} />}
        {!isImage && isEmbed && (
          <iframe src={`${src}?autoplay=1`} title={title || ""} allow="autoplay; encrypted-media; fullscreen" allowFullScreen />
        )}
        {!isImage && !isEmbed && url && (
          <video src={url} controls autoPlay />
        )}
      </div>
      {(title || description) && (
        <div className="lb-caption" onClick={(e) => e.stopPropagation()}>
          <div className="lb-caption-row">
            <h4>{title}</h4>
            {year && <span>{year}</span>}
          </div>
          {description && <p>{description}</p>}
        </div>
      )}
      {total > 1 && <div className="lb-count" onClick={(e) => e.stopPropagation()}>{index + 1} / {total}</div>}
    </div>
  );
}

// ─── Auto-derive a YouTube thumbnail from a watch URL ──────────────────
function youtubeThumb(url) {
  if (!url) return null;
  let id = null;
  let m = url.match(/youtube\.com\/watch\?v=([^&]+)/);
  if (m) id = m[1];
  if (!id) { m = url.match(/youtu\.be\/([^?]+)/); if (m) id = m[1]; }
  if (!id) { m = url.match(/youtube\.com\/embed\/([^?]+)/); if (m) id = m[1]; }
  if (!id) return null;
  return `https://img.youtube.com/vi/${id}/maxresdefault.jpg`;
}

// Treat anything explicitly tagged "image" — or anything whose URL looks
// like an image — as a still. Defaults to "video" for backward compat.
const looksLikeImage = (u) => /\.(jpe?g|png|gif|webp|avif|svg)(\?|$)/i.test(u || "");
const videoIsImage = (video) => video.mediaType === "image" || (!video.mediaType && looksLikeImage(video.url));

function VideoCard({ index, video, total, onOpen }) {
  const { isAdmin, data, update } = React.useContext(AdminCtx);
  const [posterError, setPosterError] = React.useState(false);

  const isImage = videoIsImage(video);

  // Poster preference: explicit thumbnail, else YouTube auto-thumb.
  const poster = !isImage && (video.thumbnail || (!posterError && youtubeThumb(video.url)));
  const isMp4 = !isImage && video.url && !/(youtube|vimeo|youtu\.be)/.test(video.url);

  const spanClass = `video span-${video.span || 6}`;

  const handleClick = () => {
    if (isAdmin || !video.url) return;
    onOpen();
  };

  return (
    <div className={spanClass}>
      <div className="video-frame" onClick={handleClick}>
        {isImage ? (
          <>
            {video.url ? (
              <img src={video.url} alt={video.title} style={{ width: "100%", height: "100%", objectFit: "cover", display: "block" }} />
            ) : (
              <div className="placeholder">
                <div className="play-btn" style={{ background: "var(--bg-3)" }}>
                  <svg viewBox="0 0 24 24" fill="var(--accent)"><path d="M21 19V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z" /></svg>
                </div>
              </div>
            )}
            <div className="bracket tl" />
            <div className="bracket tr" />
            <div className="bracket bl" />
            <div className="bracket br" />
            <div className="idx">IMG · {String(index + 1).padStart(2, "0")} / {String(total).padStart(2, "0")}</div>
          </>
        ) : (
          <>
            {poster ? (
              <>
                <img
                  src={poster}
                  alt={video.title}
                  onError={() => setPosterError(true)}
                  style={{ width: "100%", height: "100%", objectFit: "cover", display: "block" }}
                />
                <div className="play-btn-overlay">
                  <div className="play-btn">
                    <svg viewBox="0 0 24 24"><path d="M8 5v14l11-7z" /></svg>
                  </div>
                </div>
              </>
            ) : isMp4 ? (
              // Show first frame of MP4 as preview (browser does this for free)
              <>
                <video
                  src={video.url}
                  preload="metadata"
                  muted
                  playsInline
                  style={{ width: "100%", height: "100%", objectFit: "cover", display: "block" }}
                />
                <div className="play-btn-overlay">
                  <div className="play-btn">
                    <svg viewBox="0 0 24 24"><path d="M8 5v14l11-7z" /></svg>
                  </div>
                </div>
              </>
            ) : (
              <div className="placeholder">
                <div className="play-btn">
                  <svg viewBox="0 0 24 24"><path d="M8 5v14l11-7z" /></svg>
                </div>
              </div>
            )}
            <div className="bracket tl" />
            <div className="bracket tr" />
            <div className="bracket bl" />
            <div className="bracket br" />
            <div className="idx">REEL · {String(index + 1).padStart(2, "0")} / {String(total).padStart(2, "0")}</div>
            <div className="timecode"><EText section="videos" sub={[index, "timecode"]} /></div>
          </>
        )}
      </div>
      <div className="video-meta">
        <h3 className="video-title"><EText section="videos" sub={[index, "title"]} /></h3>
        <span className="video-year"><EText section="videos" sub={[index, "year"]} /></span>
      </div>
      <p className="video-desc"><EText section="videos" sub={[index, "description"]} multiline /></p>
      <div className="video-tags">
        {(video.tags || []).map((tag, ti) => (
          <span key={ti} className="tag" style={{ fontSize: 10, padding: "3px 8px" }}>
            <EText section="videos" sub={[index, "tags", ti]} />
          </span>
        ))}
      </div>
      {isAdmin && (
        <div style={{ marginTop: 12, padding: 12, background: "var(--bg-2)", border: "1px solid var(--line)", display: "flex", flexDirection: "column", gap: 14 }}>
          <div>
            <label style={{ fontFamily: "var(--mono)", fontSize: 10, textTransform: "uppercase", letterSpacing: "0.1em", color: "var(--mute)", display: "block", marginBottom: 6 }}>
              // Media type
            </label>
            <div style={{ display: "flex", gap: 6 }}>
              {[
                { v: "video", label: "Video" },
                { v: "image", label: "Image" },
              ].map(({ v, label }) => {
                const on = (video.mediaType || "video") === v;
                return (
                  <button
                    key={v}
                    onClick={() => {
                      const next = data.videos.map((it, i) => (i === index ? { ...it, mediaType: v } : it));
                      update("videos", next);
                    }}
                    style={{
                      flex: 1,
                      padding: "8px 10px",
                      fontFamily: "var(--mono)",
                      fontSize: 11,
                      background: on ? "var(--accent)" : "var(--bg)",
                      color: on ? "var(--bg)" : "var(--ink-2)",
                      border: "1px solid " + (on ? "var(--accent)" : "var(--line)"),
                      cursor: "pointer",
                    }}
                  >{label}</button>
                );
              })}
            </div>
          </div>
          <EFileField
            section="videos"
            sub={[index, "url"]}
            label={isImage ? "// Image — upload or paste URL" : "// Video — upload or paste URL"}
            accept={isImage ? "image/*" : "video/*,image/*"}
            folder={isImage ? "images" : "videos"}
            hint={
              isImage
                ? "// JPG, PNG, WebP — uploads → Cloudflare R2."
                : "// MP4 upload, or paste a YouTube / Vimeo URL."
            }
          />
          {!isImage && (
            <EFileField
              section="videos"
              sub={[index, "thumbnail"]}
              label="// Custom thumbnail (optional)"
              accept="image/*"
              folder="thumbnails"
              hint="// YouTube thumbnails are auto-detected. For MP4s/Vimeo, upload a poster image here, otherwise the first frame is used."
            />
          )}
          <div>
            <label style={{ fontFamily: "var(--mono)", fontSize: 10, textTransform: "uppercase", letterSpacing: "0.1em", color: "var(--mute)", display: "block", marginBottom: 6 }}>
              // Layout width
            </label>
            <div style={{ display: "flex", gap: 6 }}>
              {[5, 6, 7, 12].map((w) => (
                <button
                  key={w}
                  onClick={() => {
                    const next = data.videos.map((v, i) => (i === index ? { ...v, span: w } : v));
                    update("videos", next);
                  }}
                  style={{
                    flex: 1,
                    padding: "8px 10px",
                    fontFamily: "var(--mono)",
                    fontSize: 11,
                    background: (video.span || 6) === w ? "var(--accent)" : "var(--bg)",
                    color: (video.span || 6) === w ? "var(--bg)" : "var(--ink-2)",
                    border: "1px solid " + ((video.span || 6) === w ? "var(--accent)" : "var(--line)"),
                    cursor: "pointer",
                  }}
                >{w === 12 ? "Full" : `${w}/12`}</button>
              ))}
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

// A single horizontally-scrolling strip of reel cards (all videos, or all
// images). Cards keep their card-level admin "Layout width" as a flex
// width instead of a grid span, and are always reachable by scrolling —
// nothing is ever clipped off-screen.
function ReelRow({ label, videos, indices, onOpen, onAdd, onRemove, onMove }) {
  const { isAdmin } = React.useContext(AdminCtx);
  const rowRef = React.useRef(null);
  const dragRef = React.useRef(null);

  const scrollByAmount = (dir) => {
    const row = rowRef.current;
    if (!row) return;
    row.scrollBy({ left: dir * Math.min(row.clientWidth * 0.8, 600), behavior: "smooth" });
  };

  const onRowMouseDown = (e) => {
    if (e.target.closest("button, a, input, textarea, [data-editable]")) return;
    dragRef.current = { x: e.clientX, scrollLeft: rowRef.current.scrollLeft, moved: false };
  };
  const onRowMouseMove = (e) => {
    if (!dragRef.current) return;
    const dx = e.clientX - dragRef.current.x;
    if (Math.abs(dx) > 4) dragRef.current.moved = true;
    rowRef.current.scrollLeft = dragRef.current.scrollLeft - dx;
  };
  const endDrag = () => { dragRef.current = null; };

  if (!isAdmin && indices.length === 0) return null;

  return (
    <div className="reel-row-wrap">
      <div className="reel-row-head">
        <span className="reel-row-label">{label}</span>
        <div className="reel-row-nav">
          <button type="button" onClick={() => scrollByAmount(-1)} aria-label={`Scroll ${label} left`}>‹</button>
          <button type="button" onClick={() => scrollByAmount(1)} aria-label={`Scroll ${label} right`}>›</button>
        </div>
      </div>
      <div
        className="reel-row"
        ref={rowRef}
        onMouseDown={onRowMouseDown}
        onMouseMove={onRowMouseMove}
        onMouseUp={endDrag}
        onMouseLeave={endDrag}
      >
        {indices.map((i, pos) => (
          <div key={i} className="reel-card">
            <VideoCard index={i} video={videos[i]} total={videos.length} onOpen={() => onOpen(i)} />
            {isAdmin && (
              <div className="elist-controls" data-noncommentable>
                <button onClick={() => onMove(i, indices[pos - 1])} title="Move left" disabled={pos === 0}>←</button>
                <button onClick={() => onMove(i, indices[pos + 1])} title="Move right" disabled={pos === indices.length - 1}>→</button>
                <button onClick={() => onRemove(i)} title="Remove" className="danger">✕</button>
              </div>
            )}
          </div>
        ))}
        {isAdmin && (
          <button type="button" className="reel-add" onClick={onAdd} data-noncommentable>
            + Add {label.toLowerCase().replace(/s$/, "")}
          </button>
        )}
      </div>
    </div>
  );
}

function VideosSection() {
  const { data, update } = React.useContext(AdminCtx);
  const videos = data.videos || [];
  const [openIndex, setOpenIndex] = React.useState(null); // index into `navigable`

  // Only pieces with actual media can be previewed; map each video's
  // position in `videos` to its position in that navigable subset.
  const navigable = React.useMemo(
    () => videos
      .filter((v) => v.url)
      .map((v) => ({ url: v.url, title: v.title, year: v.year, description: v.description, isImage: videoIsImage(v) })),
    [videos]
  );
  const navIndexMap = React.useMemo(() => {
    let c = -1;
    return videos.map((v) => (v.url ? (c += 1) : -1));
  }, [videos]);

  const videoIndices = [];
  const imageIndices = [];
  videos.forEach((v, i) => (videoIsImage(v) ? imageIndices : videoIndices).push(i));

  const openAt = (i) => { if (navIndexMap[i] !== -1) setOpenIndex(navIndexMap[i]); };
  const removeAt = (i) => update("videos", videos.filter((_, idx) => idx !== i));
  const swap = (i, j) => {
    if (j === undefined) return;
    const next = videos.slice();
    [next[i], next[j]] = [next[j], next[i]];
    update("videos", next);
  };
  const addPiece = (mediaType) => update("videos", [
    ...videos,
    {
      title: "New piece", year: "2026", description: "Add a short description.",
      url: "", thumbnail: "", tags: [mediaType === "image" ? "design" : "motion"],
      timecode: "00:00:30:00", span: 6, mediaType,
    },
  ]);

  return (
    <section id="reel">
      <SectionHead
        numKey="videosNum"
        prePart="videosTitlePre"
        accentPart="videosTitleAccent"
        sufPart="videosTitleSuf"
        aside1Key="videosAside1"
        aside2Key="videosAside2"
      />
      <ReelRow
        label="Videos"
        videos={videos}
        indices={videoIndices}
        onOpen={openAt}
        onAdd={() => addPiece("video")}
        onRemove={removeAt}
        onMove={swap}
      />
      <ReelRow
        label="Images"
        videos={videos}
        indices={imageIndices}
        onOpen={openAt}
        onAdd={() => addPiece("image")}
        onRemove={removeAt}
        onMove={swap}
      />
      {openIndex !== null && (
        <Lightbox
          items={navigable}
          index={openIndex}
          onClose={() => setOpenIndex(null)}
          onNavigate={setOpenIndex}
        />
      )}
    </section>
  );
}

// ─── Certificates ───────────────────────────────────────────────────────

function CertsSection() {
  const { data } = React.useContext(AdminCtx);
  return (
    <section id="certs">
      <SectionHead
        numKey="certsNum"
        prePart="certsTitlePre"
        accentPart="certsTitleAccent"
        sufPart="certsTitleSuf"
        aside1Key="certsAside1"
        aside2Key="certsAside2"
      />
      <div className="certs">
        <EList
          section="certs"
          template={() => ({ title: "New certificate", issuer: "Issuer", year: "2026", image: "" })}
          label="certificate"
          renderItem={(c, i) => (
            <div className="cert">
              <div className="cert-image">
                {c.image
                  ? <EImage section="certs" sub={[i, "image"]} placeholderText="Certificate" />
                  : (
                    <div className="placeholder">
                      <div className="seal">✓</div>
                      <div>{String(i + 1).padStart(2, "0")} / Certified</div>
                    </div>
                  )
                }
              </div>
              <div className="cert-body">
                <h3 className="cert-title"><EText section="certs" sub={[i, "title"]} /></h3>
                <div className="cert-issuer">↳ <EText section="certs" sub={[i, "issuer"]} /></div>
                <div className="cert-year"><EText section="certs" sub={[i, "year"]} /></div>
              </div>
            </div>
          )}
        />
      </div>
    </section>
  );
}

// ─── CV ─────────────────────────────────────────────────────────────────

function CVSection() {
  const { isAdmin, data } = React.useContext(AdminCtx);
  const cvUrl = data.cv?.pdfUrl || "";

  return (
    <section id="cv">
      <SectionHead
        numKey="cvNum"
        prePart="cvTitlePre"
        accentPart="cvTitleAccent"
        sufPart="cvTitleSuf"
        aside1Key="cvAside1"
        aside2Key="cvAside2"
      />
      <div className="cv reveal">
        <div className="cv-doc">
          <div className="doc-hd"><EText section="cv" sub="docName" /></div>
          <div className="doc-sub"><EText section="cv" sub="docRole" /></div>
          <div className="doc-section"><EText section="cv" sub="docSection1" /></div>
          <div className="doc-line l" />
          <div className="doc-line l" />
          <div className="doc-line m" />
          <div className="doc-section"><EText section="cv" sub="docSection2" /></div>
          <div className="doc-line l" />
          <div className="doc-line s" />
          <div className="doc-line m" />
          <div className="doc-line l" />
          <div className="doc-section"><EText section="cv" sub="docSection3" /></div>
          <div className="doc-line m" />
          <div className="doc-line s" />
        </div>
        <div className="cv-text">
          <h3><EText section="cv" sub="headline" /></h3>
          <p><EText section="cv" sub="summary" multiline /></p>
          <div className="cv-buttons">
            {cvUrl ? (
              <>
                <a className="btn" href={cvUrl} target="_blank" rel="noreferrer">
                  <svg viewBox="0 0 16 16" fill="currentColor"><path d="M8 1v8.5l3-3 1 1L8 12l-4-4.5 1-1 3 3V1h1zM3 13h10v1H3v-1z" /></svg>
                  <L k="cvDownloadBtn" />
                </a>
                <a className="btn ghost" href={cvUrl} target="_blank" rel="noreferrer">
                  <L k="cvViewBtn" />
                </a>
              </>
            ) : (
              <span style={{ fontFamily: "var(--mono)", fontSize: 12, color: "var(--mute)", letterSpacing: "0.06em", textTransform: "uppercase" }}>
                {isAdmin ? "// Add a PDF URL below to activate the buttons" : <L k="cvNoFileMsg" />}
              </span>
            )}
          </div>
          <div className="cv-updated">// Last updated · <b><EText section="cv" sub="updated" /></b></div>
          {isAdmin && (
            <div style={{ marginTop: 20, padding: 14, background: "var(--bg)", border: "1px solid var(--line)" }}>
              <EFileField
                section="cv"
                sub="pdfUrl"
                label="// CV PDF — upload or paste URL"
                accept="application/pdf"
                folder="cv"
                hint="// Tip: Google Drive PDFs also work — share → 'Anyone with link' → paste."
              />
            </div>
          )}
        </div>
      </div>
    </section>
  );
}

// ─── Contact ────────────────────────────────────────────────────────────

function ContactSection() {
  const { data } = React.useContext(AdminCtx);
  return (
    <section className="contact" id="contact">
      <div className="reveal">
        <div className="contact-eyebrow">
          <span style={{ color: "var(--accent)" }}>[</span>
          <span className="led" style={{ display: "inline-block", width: 7, height: 7, borderRadius: "50%", background: "var(--accent)", boxShadow: "0 0 12px var(--accent)" }} />
          <L k="contactNum" />
          <span style={{ color: "var(--accent)" }}>]</span>
        </div>
        <h2>
          <L k="contactTitleL1" /><br />
          <L k="contactTitleL2" /><em><L k="contactTitleAccent" /></em><L k="contactTitleSuf" />
        </h2>
        <p className="lede"><EText section="contact" sub="lede" multiline /></p>

        <div className="contact-grid">
          <div>
            <div className="mono" style={{ marginBottom: 14 }}><L k="contactEmailLbl" /></div>
            <a className="contact-email" href={`mailto:${data.contact?.email || ""}`}>
              <EText section="contact" sub="email" />
              <span className="arrow">↗</span>
            </a>
          </div>
          <div>
            <div className="mono" style={{ marginBottom: 14 }}><L k="contactSocialsLbl" /></div>
            <div className="contact-socials">
              <EList
                section="contact"
                sub="socials"
                template={() => ({ name: "Platform", url: "#", handle: "@you" })}
                label="link"
                renderItem={(s, i) => (
                  <a href={s.url || "#"} target="_blank" rel="noreferrer">
                    <span>
                      <EText section="contact" sub={["socials", i, "name"]} />
                      <span style={{ color: "var(--mute)", marginLeft: 12, fontWeight: 400 }}>
                        <EText section="contact" sub={["socials", i, "handle"]} />
                      </span>
                    </span>
                    <span className="arr">→</span>
                  </a>
                )}
              />
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

// ─── Footer ─────────────────────────────────────────────────────────────

function Footer() {
  const { data, isAdmin } = React.useContext(AdminCtx);
  const year = new Date().getFullYear();
  return (
    <footer>
      <div>© {year} · <EText section="signature" /> · <L k="footerTagline" /></div>
      <div className="center"><L k="footerTypeLine" /></div>
      <div className="right">
        <b><L k="footerVersion" /></b> · {isAdmin && <span>STUDIO MODE · </span>}<LiveClock tz="Africa/Cairo" /> CAI
      </div>
    </footer>
  );
}

// ─── Cloud status banner ────────────────────────────────────────────────

function CloudBanner({ status }) {
  const [dismissed, setDismissed] = React.useState(() => {
    try { return sessionStorage.getItem("cloud-banner-dismissed") === "1"; } catch (e) { return false; }
  });

  React.useEffect(() => {
    const slot = document.getElementById("cloud-banner");
    if (!slot) return;
    if (!status.ready || status.mode === "cloud" || dismissed) {
      slot.innerHTML = "";
      return;
    }
    slot.innerHTML = `
      <div style="display:flex;align-items:center;justify-content:center;gap:12px;flex-wrap:wrap">
        <span>// LOCAL MODE — saves to this browser only. Deploy to Cloudflare for cross-device sync.</span>
        <button id="cloud-banner-x" style="background:none;border:0;font-size:18px;cursor:pointer;line-height:1;color:inherit">×</button>
      </div>
    `;
    const dismiss = () => {
      try { sessionStorage.setItem("cloud-banner-dismissed", "1"); } catch (e) {}
      setDismissed(true);
    };
    document.getElementById("cloud-banner-x")?.addEventListener("click", dismiss);
  }, [status, dismissed]);
  return null;
}

// ─── Site settings panel ────────────────────────────────────────────────

function SiteSettingsModal({ onClose, exportBackup, importBackup }) {
  const { data, update } = React.useContext(AdminCtx);
  const site = data.site || {};
  const setField = (k, v) => update("site", { ...site, [k]: v });
  const fileRef = React.useRef(null);
  const [importStatus, setImportStatus] = React.useState({ kind: null, message: "" });

  const onImport = async (file) => {
    if (!file) return;
    if (!confirm("Restore from this backup? This will REPLACE everything currently on your site. Make sure you've exported a backup of your current data first.")) return;
    setImportStatus({ kind: "busy", message: "// restoring…" });
    try {
      await importBackup(file);
      setImportStatus({ kind: "ok", message: "// restored successfully" });
    } catch (e) {
      setImportStatus({ kind: "err", message: "// " + (e.message || "import failed") });
    }
  };

  return (
    <div className="login-backdrop" onClick={onClose}>
      <div className="config-card" onClick={(e) => e.stopPropagation()} style={{ maxHeight: "90vh" }}>
        <div className="login-corner tl" />
        <div className="login-corner tr" />
        <div className="login-corner bl" />
        <div className="login-corner br" />

        <div className="login-tag">[ SITE / SETTINGS ]</div>
        <h3>Link preview</h3>
        <p className="login-sub" style={{ marginBottom: 24 }}>
          // What people see when they share your link
        </p>

        <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
          <div>
            <label style={{ fontFamily: "var(--mono)", fontSize: 10.5, letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--mute)", display: "block", marginBottom: 8 }}>
              // Site title
            </label>
            <input
              type="text"
              value={site.title || ""}
              onChange={(e) => setField("title", e.target.value)}
              placeholder="Abdallah — Multimedia Designer"
              style={{ width: "100%", padding: "10px 12px", background: "var(--bg)", border: "1px solid var(--line)", color: "var(--ink)", fontFamily: "var(--mono)", fontSize: 13, outline: "none" }}
            />
          </div>

          <div>
            <label style={{ fontFamily: "var(--mono)", fontSize: 10.5, letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--mute)", display: "block", marginBottom: 8 }}>
              // Description
            </label>
            <textarea
              value={site.description || ""}
              onChange={(e) => setField("description", e.target.value)}
              placeholder="Motion · 3D · Brand · Editorial."
              rows={2}
              style={{ width: "100%", padding: "10px 12px", background: "var(--bg)", border: "1px solid var(--line)", color: "var(--ink)", fontFamily: "var(--mono)", fontSize: 13, outline: "none", resize: "vertical", minHeight: 56 }}
            />
          </div>
        </div>

        {/* Backup / Restore section — ESSENTIAL safety net */}
        <div style={{ marginTop: 28, paddingTop: 24, borderTop: "1px solid var(--line)" }}>
          <div className="login-tag" style={{ textAlign: "left", marginBottom: 8 }}>[ BACKUP / RESTORE ]</div>
          <p className="login-sub" style={{ textAlign: "left", margin: "0 0 16px" }}>
            // Save a local copy of all your data. Do this regularly.
          </p>

          <div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
            <button
              type="button"
              className="btn-mini primary"
              onClick={exportBackup}
              style={{ padding: "10px 16px" }}
            >
              ↓ Export backup (.json)
            </button>
            <button
              type="button"
              className="btn-mini"
              onClick={() => fileRef.current?.click()}
              style={{ padding: "10px 16px" }}
            >
              ↑ Restore from backup
            </button>
            <input
              ref={fileRef}
              type="file"
              accept="application/json,.json"
              style={{ display: "none" }}
              onChange={(e) => {
                onImport(e.target.files?.[0]);
                e.target.value = ""; // allow re-uploading same file
              }}
            />
          </div>

          {importStatus.kind && (
            <div
              style={{
                marginTop: 12,
                padding: "10px 12px",
                fontFamily: "var(--mono)",
                fontSize: 11.5,
                letterSpacing: "0.04em",
                color: importStatus.kind === "err" ? "var(--red)"
                     : importStatus.kind === "ok"  ? "var(--accent)"
                     : "var(--ink-2)",
                background: importStatus.kind === "err" ? "color-mix(in oklab, var(--red) 12%, transparent)"
                          : importStatus.kind === "ok"  ? "color-mix(in oklab, var(--accent) 10%, transparent)"
                          : "var(--bg)",
                border: `1px solid ${importStatus.kind === "err" ? "var(--red)" : importStatus.kind === "ok" ? "var(--accent)" : "var(--line)"}`,
              }}
            >
              {importStatus.message}
            </div>
          )}

          <p className="config-hint" style={{ marginTop: 16 }}>
            // <b>Tip:</b> Export a backup every time you make significant changes. The .json file contains all your text edits — keep it somewhere safe (Google Drive, Dropbox). If anything ever goes wrong, click Restore and pick the file to get everything back.
          </p>
        </div>

        <div className="login-actions">
          <button className="btn-mini primary" onClick={onClose}>→ Done</button>
        </div>
      </div>
    </div>
  );
}

window.SiteSettingsModal = SiteSettingsModal;

function App() {
  const { data, update, status, exportBackup, importBackup } = useStore();
  const { isAdmin, login, logout, showLogin, setShowLogin } = useAdmin();
  const [showConfig, setShowConfig] = React.useState(false);
  const [showSettings, setShowSettings] = React.useState(false);

  React.useEffect(() => {
    document.documentElement.dataset.theme = data.theme || "lime";
  }, [data.theme]);

  // Keep the browser tab title + meta description in sync with the
  // editable site fields. Note: link-preview crawlers (WhatsApp/Twitter/etc)
  // read the static HTML and never run this — they show whatever was in
  // the file when they first scraped it. Editing here updates only what
  // live visitors see in the tab.
  React.useEffect(() => {
    const t = data.site?.title;
    if (t) document.title = t;
    const d = data.site?.description;
    if (d) {
      const setMeta = (selector, attr) => {
        const el = document.querySelector(selector);
        if (el) el.setAttribute(attr, d);
      };
      setMeta('meta[name="description"]', "content");
      setMeta('meta[property="og:description"]', "content");
    }
    if (t) {
      const setMeta = (selector, attr) => {
        const el = document.querySelector(selector);
        if (el) el.setAttribute(attr, t);
      };
      setMeta('meta[property="og:title"]', "content");
    }
  }, [data.site?.title, data.site?.description]);

  if (!status.ready) {
    return (
      <div style={{ position: "fixed", inset: 0, display: "flex", alignItems: "center", justifyContent: "center", fontFamily: "var(--mono)", fontSize: 12, color: "var(--mute)", letterSpacing: "0.1em", textTransform: "uppercase" }}>
        // booting studio…
      </div>
    );
  }

  return (
    <EditProvider isAdmin={isAdmin} data={data} update={update}>
      <EditStyles />
      <AdminStyles />
      <CloudBanner status={status} />

      <Nav
        isAdmin={isAdmin}
        signature={data.signature}
        onLockClick={() => (isAdmin ? setShowConfig(true) : setShowLogin(true))}
      />

      <main className="page">
        <Hero />
      </main>
      <MarqueeBar />
      <main className="page">
        <AboutSection />
        <SkillsSection />
        <VideosSection />
        <CertsSection />
        <CVSection />
        <ContactSection />
      </main>
      <Footer />

      {isAdmin && (
        <AdminToolbar
          status={status}
          onLogout={logout}
          onConfigOpen={() => setShowConfig(true)}
          onSettingsOpen={() => setShowSettings(true)}
        />
      )}

      {showLogin && (
        <LoginModal
          onSubmit={login}
          onClose={() => setShowLogin(false)}
        />
      )}

      {showConfig && (
        <ConfigModal
          status={status}
          onClose={() => setShowConfig(false)}
        />
      )}

      {showSettings && (
        <SiteSettingsModal
          onClose={() => setShowSettings(false)}
          exportBackup={exportBackup}
          importBackup={importBackup}
        />
      )}
    </EditProvider>
  );
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
