/* global React */
(function(){
const { useState, useRef } = React;

/* =============================================================
   ShareFrame.jsx — "قاب کشوردوست"
   --------------------------------------------------------------
   Outer aspect (the whole image):
     story  → 9:16  · inner content 3:4   (vertical reel feel)
     مربع  → 3:4   · inner content 1:1   (square content, vertical frame)
     افقی  → 1:1   · inner content 4:3   (landscape content, square frame)
   Caption: one line, ellipsised.
   Download button: builds a real PNG via canvas and triggers save.
   ============================================================= */

const fmtFa = (n) => String(n).replace(/\d/g, d => "۰۱۲۳۴۵۶۷۸۹"[d]);

const NETWORK_META = {
  bale:      { label: "بَله",       glyph: "B",  color: "#2C7DFA" },
  eitaa:     { label: "ایتا",       glyph: "E",  color: "#FFA300" },
  virasti:   { label: "ویراستی",    glyph: "و",  color: "#7A4DFF" },
  wisgoon:   { label: "ویسگون",     glyph: "س",  color: "#F1535E" },
  rubika:    { label: "روبیکا",     glyph: "R",  color: "#FF1E56" },
  twitter:   { label: "X",          glyph: "𝕏", color: "#101418" },
  instagram: { label: "اینستاگرام", glyph: "◯", color: "#E1306C" },
  telegram:  { label: "تلگرام",     glyph: "✈", color: "#229ED9" },
  facebook:  { label: "فیسبوک",     glyph: "f",  color: "#1877F2" },
};

// Outer aspect = frame, inner aspect = content card inside the frame
const LAYOUTS = [
  { id: "story",  label: "استوری", outer: "9 / 16", inner: "3 / 4", w: 220 },
  { id: "square", label: "مربع",   outer: "3 / 4",  inner: "1 / 1", w: 270 },
  { id: "wide",   label: "افقی",   outer: "1 / 1",  inner: "4 / 3", w: 320 },
];

const THEMES = [
  { id: "neon",     label: "نِئون",   bg: "linear-gradient(160deg, #ff4ea8 0%, #9a6cff 50%, #4be3ff 100%)",   fg: "#fff",     canvas: ["#ff4ea8", "#9a6cff", "#4be3ff"] },
  { id: "ember",    label: "آتش",     bg: "linear-gradient(160deg, #ff8a3d 0%, #ff4ea8 100%)",                fg: "#fff",     canvas: ["#ff8a3d", "#ff4ea8"] },
  { id: "midnight", label: "نیمه‌شب", bg: "linear-gradient(160deg, #08111e 0%, #1a0e2e 100%)",                fg: "#fff",     canvas: ["#08111e", "#1a0e2e"] },
  { id: "gold",     label: "طلایی",   bg: "linear-gradient(160deg, #c08a2e 0%, #2a1a06 100%)",                fg: "#f5d589",  canvas: ["#c08a2e", "#2a1a06"] },
];

const SHARE_TARGETS = [
  { id: "telegram",  label: "تلگرام",        glyph: "✈", color: "#229ED9", bg: "linear-gradient(135deg,#229ED9,#0088cc)" },
  { id: "instagram", label: "اینستاگرام",    glyph: "◯", color: "#E1306C", bg: "linear-gradient(135deg,#833AB4,#FD1D1D,#FCB045)" },
  { id: "twitter",   label: "X / توییتر",    glyph: "𝕏", color: "#101418", bg: "linear-gradient(135deg,#000,#222)" },
  { id: "facebook",  label: "فیسبوک",        glyph: "f", color: "#1877F2", bg: "linear-gradient(135deg,#1877F2,#0a5fc0)" },
  { id: "whatsapp",  label: "واتساپ",        glyph: "✓", color: "#25D366", bg: "linear-gradient(135deg,#25D366,#128C7E)" },
  { id: "bale",      label: "بَله",          glyph: "B", color: "#2C7DFA", bg: "linear-gradient(135deg,#2C7DFA,#1a4ea8)" },
  { id: "eitaa",     label: "ایتا",          glyph: "E", color: "#FFA300", bg: "linear-gradient(135deg,#FFA300,#cc7700)" },
  { id: "rubika",    label: "روبیکا",        glyph: "R", color: "#FF1E56", bg: "linear-gradient(135deg,#FF1E56,#a8003a)" },
  { id: "virasti",   label: "ویراستی",       glyph: "و", color: "#7A4DFF", bg: "linear-gradient(135deg,#7A4DFF,#4a26b8)" },
  { id: "wisgoon",   label: "ویسگون",        glyph: "س", color: "#F1535E", bg: "linear-gradient(135deg,#F1535E,#a82a35)" },
  { id: "download",  label: "دانلود",        glyph: null, color: "#fff",    bg: "linear-gradient(135deg,#ff4ea8,#9a6cff)" },
];

const OUTER_PX = {
  story:  { w: 1080, h: 1920 },
  square: { w: 1080, h: 1440 },
  wide:   { w: 1080, h: 1080 },
};
const INNER_RATIO = {
  story:  { w: 3, h: 4 },
  square: { w: 1, h: 1 },
  wide:   { w: 4, h: 3 },
};

/* ----- Canvas helpers ------------------------------------------ */
function roundedRectPath(ctx, x, y, w, h, r) {
  const rr = Math.min(r, w / 2, h / 2);
  ctx.beginPath();
  ctx.moveTo(x + rr, y);
  ctx.arcTo(x + w, y, x + w, y + h, rr);
  ctx.arcTo(x + w, y + h, x, y + h, rr);
  ctx.arcTo(x, y + h, x, y, rr);
  ctx.arcTo(x, y, x + w, y, rr);
  ctx.closePath();
}
function drawDiagGrad(ctx, x, y, w, h, stops) {
  const g = ctx.createLinearGradient(x, y, x + w, y + h);
  stops.forEach((c, i) => g.addColorStop(i / (stops.length - 1), c));
  ctx.fillStyle = g;
  ctx.fillRect(x, y, w, h);
}
function drawRadial(ctx, cx, cy, r, color) {
  const g = ctx.createRadialGradient(cx, cy, 0, cx, cy, r);
  g.addColorStop(0, color);
  g.addColorStop(1, color.replace(/[\d.]+\)$/, "0)"));
  ctx.fillStyle = g;
  ctx.fillRect(cx - r, cy - r, r * 2, r * 2);
}
function truncate(str, max) {
  if (!str) return "";
  if (str.length <= max) return str;
  return str.slice(0, max - 1) + "…";
}

/* Truncate a string with the ellipsis to fit a given pixel width on the
   current canvas context (must have font set). */
function truncateToWidth(ctx, str, maxW) {
  if (!str) return "";
  if (ctx.measureText(str).width <= maxW) return str;
  let lo = 0, hi = str.length;
  while (lo < hi) {
    const mid = (lo + hi) >> 1;
    const t = str.slice(0, mid) + "…";
    if (ctx.measureText(t).width <= maxW) lo = mid + 1;
    else hi = mid;
  }
  return str.slice(0, Math.max(0, lo - 1)) + "…";
}

/* Draws a star ★ centered on (cx,cy) with given radius. */
function drawStar(ctx, cx, cy, r, color) {
  ctx.save();
  ctx.fillStyle = color;
  ctx.beginPath();
  for (let i = 0; i < 10; i++) {
    const a = (Math.PI / 5) * i - Math.PI / 2;
    const rr = i % 2 === 0 ? r : r * 0.45;
    const x = cx + Math.cos(a) * rr;
    const y = cy + Math.sin(a) * rr;
    if (i === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y);
  }
  ctx.closePath();
  ctx.fill();
  ctx.restore();
}

/* renders a snapshot PNG of the current frame at high res */
function renderFrameCanvas({ layout, theme, post, showMeta, caption, NET, qrImg }) {
  const T = THEMES.find(t => t.id === theme);
  const { w, h } = OUTER_PX[layout];
  const canvas = document.createElement("canvas");
  canvas.width = w; canvas.height = h;
  const ctx = canvas.getContext("2d");

  // ---- Rounded outer corners (transparent beyond the radius)
  const outerR = Math.round(w * 0.04);
  roundedRectPath(ctx, 0, 0, w, h, outerR);
  ctx.clip();

  // ---- Background gradient
  drawDiagGrad(ctx, 0, 0, w, h, T.canvas);

  // ---- Soft noise overlay (subtle dots)
  ctx.save();
  ctx.globalAlpha = 0.07;
  for (let i = 0; i < 240; i++) {
    ctx.fillStyle = "#fff";
    ctx.fillRect(Math.random() * w, Math.random() * h, 2, 2);
  }
  ctx.restore();

  // ---- Padding
  const pad = Math.round(w * 0.045);
  const bandH = Math.round(h * 0.085);

  // ---- Inner content rect — sized by INNER_RATIO, centered
  const innerR = INNER_RATIO[layout];
  // Reserve space for caption line below the inner card
  const capH = Math.round(h * 0.038);
  const innerMaxW = w - pad * 2;
  const innerMaxH = h - bandH * 2 - pad * 2 - capH - Math.round(h * 0.012);
  let innerW = innerMaxW;
  let innerH = innerW * innerR.h / innerR.w;
  if (innerH > innerMaxH) {
    innerH = innerMaxH;
    innerW = innerH * innerR.w / innerR.h;
  }
  const innerX = (w - innerW) / 2;
  const innerY = bandH + pad + (innerMaxH - innerH) / 2;

  // ---- Inner card
  ctx.save();
  roundedRectPath(ctx, innerX, innerY, innerW, innerH, Math.round(innerW * 0.04));
  ctx.clip();
  drawDiagGrad(ctx, innerX, innerY, innerW, innerH, ["#1a0a22", "#08111e"]);
  drawRadial(ctx, innerX + innerW * 0.25, innerY + innerH * 0.25, innerW * 0.7, "rgba(255,78,168,0.45)");
  drawRadial(ctx, innerX + innerW * 0.8,  innerY + innerH * 0.8,  innerW * 0.65, "rgba(75,227,255,0.35)");

  // play badge for video/audio
  if (post.kind === "video" || post.kind === "audio") {
    const pr = Math.round(innerW * 0.09);
    const px = innerX + innerW / 2, py = innerY + innerH / 2;
    ctx.fillStyle = "rgba(255,255,255,0.95)";
    ctx.beginPath(); ctx.arc(px, py, pr, 0, Math.PI * 2); ctx.fill();
    ctx.fillStyle = "#0a1018";
    ctx.beginPath();
    ctx.moveTo(px - pr*0.32, py - pr*0.42);
    ctx.lineTo(px + pr*0.45, py);
    ctx.lineTo(px - pr*0.32, py + pr*0.42);
    ctx.closePath(); ctx.fill();
  }

  // network badge on inner media (RTL → inline-start = top-right corner)
  if (NET) {
    const br = Math.round(w * 0.045);
    const bx = innerX + innerW - pad * 0.8 - br;
    const by = innerY + pad * 0.8 + br;
    ctx.fillStyle = NET.color;
    ctx.beginPath(); ctx.arc(bx, by, br, 0, Math.PI * 2); ctx.fill();
    ctx.strokeStyle = "rgba(255,255,255,0.25)"; ctx.lineWidth = 4;
    ctx.beginPath(); ctx.arc(bx, by, br, 0, Math.PI * 2); ctx.stroke();
    ctx.fillStyle = "#fff";
    ctx.font = `bold ${Math.round(br * 1.05)}px Tahoma, sans-serif`;
    ctx.textAlign = "center"; ctx.textBaseline = "middle";
    ctx.fillText(NET.glyph, bx, by + 2);
  }

  ctx.restore();

  // ---- Author/meta strip — overlaid on bottom of inner card, RTL layout
  if (showMeta) {
    const stripH = Math.round(h * 0.085);
    const stripY = innerY + innerH - stripH;
    ctx.save();
    // backdrop
    ctx.fillStyle = "rgba(0,0,0,0.55)";
    ctx.fillRect(innerX, stripY, innerW, stripH);

    const av = Math.round(stripH * 0.32);
    // Avatar at inline-start (RTL → right side)
    const ax = innerX + innerW - pad - av;
    const ay = stripY + stripH / 2;
    const grad = ctx.createLinearGradient(ax - av, ay - av, ax + av, ay + av);
    grad.addColorStop(0, "#f5d589"); grad.addColorStop(1, "#c08a2e");
    ctx.fillStyle = grad; ctx.beginPath(); ctx.arc(ax, ay, av, 0, Math.PI * 2); ctx.fill();
    ctx.fillStyle = "#1a1208";
    ctx.font = `500 ${Math.round(av * 1.1)}px Tahoma, sans-serif`;
    ctx.textAlign = "center"; ctx.textBaseline = "middle";
    ctx.fillText((post.author?.name || "ن").charAt(0), ax, ay + 1);

    // Name + handle — to the LEFT of avatar (text reads RTL)
    const textRight = ax - av - Math.round(stripH * 0.16);
    ctx.fillStyle = "#fff";
    ctx.font = `700 ${Math.round(stripH * 0.28)}px Tahoma, sans-serif`;
    ctx.textAlign = "right"; ctx.textBaseline = "alphabetic"; ctx.direction = "rtl";
    ctx.fillText(post.author?.name || "نگار رستمی", textRight, ay - Math.round(stripH * 0.04));
    ctx.fillStyle = "rgba(255,255,255,0.6)";
    ctx.font = `400 ${Math.round(stripH * 0.22)}px Tahoma, sans-serif`;
    ctx.fillText(`@${post.author?.handle || "negar.r"}`, textRight, ay + Math.round(stripH * 0.28));

    // Rating — inline-end (RTL → left side)
    const rate = post.rating != null ? post.rating : 4.7;
    const starR = Math.round(stripH * 0.18);
    const starX = innerX + pad + starR;
    ctx.direction = "ltr"; ctx.textAlign = "left"; ctx.textBaseline = "middle";
    drawStar(ctx, starX, ay, starR, "#f5d589");
    ctx.fillStyle = "#f5d589";
    ctx.font = `700 ${Math.round(stripH * 0.3)}px Tahoma, sans-serif`;
    const rateTxt = (typeof rate === "number" ? rate.toFixed(1) : String(rate));
    ctx.fillText(rateTxt, starX + starR + 8, ay + 1);
    ctx.restore();
  }

  // ---- Caption — one line, right-aligned, ellipsised by pixel width
  const capText = caption || post.caption || "";
  ctx.save();
  ctx.fillStyle = T.fg; ctx.globalAlpha = 0.95;
  const capFont = Math.round(h * 0.022);
  ctx.font = `600 ${capFont}px Tahoma, sans-serif`;
  ctx.textAlign = "right"; ctx.textBaseline = "top"; ctx.direction = "rtl";
  const capY = innerY + innerH + Math.round(h * 0.012);
  const capMaxW = innerW - pad * 0.8;
  const capLine = truncateToWidth(ctx, capText, capMaxW);
  ctx.fillText(capLine, innerX + innerW - pad * 0.4, capY);
  ctx.restore();

  // ---- Top band — brand + source/tag
  ctx.save();
  // logo box (RTL → inline-start = right side)
  const lb = Math.round(bandH * 0.55);
  const lbx = w - pad - lb;
  const lby = (bandH - lb) / 2 + Math.round(h * 0.012);
  ctx.fillStyle = "rgba(0,0,0,0.4)";
  roundedRectPath(ctx, lbx, lby, lb, lb, 14); ctx.fill();
  ctx.fillStyle = "#f5d589";
  ctx.font = `500 ${Math.round(lb * 0.62)}px Tahoma, sans-serif`;
  ctx.textAlign = "center"; ctx.textBaseline = "middle";
  ctx.fillText("کـ", lbx + lb/2, lby + lb/2 + 2);

  // Brand text to the LEFT of the logo box (reads RTL)
  ctx.fillStyle = T.fg;
  ctx.textAlign = "right"; ctx.textBaseline = "alphabetic"; ctx.direction = "rtl";
  ctx.font = `500 ${Math.round(bandH * 0.3)}px Tahoma, sans-serif`;
  const txRight = lbx - 14;
  ctx.fillText("کشوردوست", txRight, lby + Math.round(bandH * 0.28));
  ctx.globalAlpha = 0.75;
  ctx.font = `400 ${Math.round(bandH * 0.2)}px Tahoma, sans-serif`;
  ctx.fillText("جشنواره محتوای ایران", txRight, lby + Math.round(bandH * 0.55));
  ctx.globalAlpha = 1;

  // tag / network chip — inline-end (RTL → left side)
  const tagH = Math.round(bandH * 0.5);
  const tagY = (bandH - tagH) / 2 + Math.round(h * 0.012);
  ctx.direction = "ltr";
  if (NET) {
    const txt = `از ${NET.label}`;
    ctx.font = `700 ${Math.round(bandH * 0.24)}px Tahoma, sans-serif`;
    const tw = ctx.measureText(txt).width + tagH + 26;
    const tx = pad;
    ctx.fillStyle = "rgba(0,0,0,0.4)";
    roundedRectPath(ctx, tx, tagY, tw, tagH, tagH / 2); ctx.fill();
    ctx.fillStyle = NET.color;
    ctx.beginPath(); ctx.arc(tx + tagH/2, tagY + tagH/2, tagH/2 - 4, 0, Math.PI * 2); ctx.fill();
    ctx.fillStyle = "#fff";
    ctx.font = `bold ${Math.round(tagH * 0.55)}px Tahoma, sans-serif`;
    ctx.textAlign = "center"; ctx.textBaseline = "middle";
    ctx.fillText(NET.glyph, tx + tagH/2, tagY + tagH/2 + 1);
    ctx.fillStyle = "#fff";
    ctx.font = `700 ${Math.round(bandH * 0.24)}px Tahoma, sans-serif`;
    ctx.textAlign = "left"; ctx.textBaseline = "middle"; ctx.direction = "rtl";
    ctx.fillText(txt, tx + tagH + 8, tagY + tagH/2 + 1);
  } else {
    const txt = post.kind === "video" ? "ویدیو" : post.kind === "image" ? "تصویر" : "اثر";
    ctx.font = `700 ${Math.round(bandH * 0.26)}px Tahoma, sans-serif`;
    const tw = ctx.measureText(txt).width + 28;
    const tx = pad;
    ctx.fillStyle = "rgba(0,0,0,0.32)";
    roundedRectPath(ctx, tx, tagY, tw, tagH, tagH / 2); ctx.fill();
    ctx.fillStyle = "#fff";
    ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.direction = "rtl";
    ctx.fillText(txt, tx + tw / 2, tagY + tagH / 2 + 1);
  }
  ctx.restore();

  // ---- Bottom band — real QR (inline-start/right) + link + hashtag
  ctx.save();
  const qrSize = Math.round(bandH * 0.78);
  const qrX = w - pad - qrSize;
  const qrY = h - bandH / 2 - qrSize / 2;
  if (qrImg) {
    // white quiet-zone card behind the QR so it stays scannable
    ctx.fillStyle = "#fff";
    roundedRectPath(ctx, qrX - 6, qrY - 6, qrSize + 12, qrSize + 12, 8);
    ctx.fill();
    ctx.drawImage(qrImg, qrX, qrY, qrSize, qrSize);
  }
  ctx.fillStyle = T.fg; ctx.globalAlpha = 0.95;
  ctx.textBaseline = "middle"; ctx.direction = "rtl";
  const linkRight = qrImg ? qrX - 16 : w - pad;
  ctx.font = `700 ${Math.round(bandH * 0.24)}px Tahoma, sans-serif`;
  ctx.textAlign = "right";
  ctx.fillText("اسکن کن و ببین", linkRight, h - bandH / 2 - Math.round(bandH * 0.16));
  ctx.globalAlpha = 0.78;
  ctx.font = `400 ${Math.round(bandH * 0.2)}px Tahoma, sans-serif`;
  ctx.direction = "ltr";
  ctx.fillText(`keshvardoost.ir/p/${post.id || "share"}`, linkRight, h - bandH / 2 + Math.round(bandH * 0.2));
  ctx.globalAlpha = 0.7;
  ctx.font = `400 ${Math.round(bandH * 0.22)}px Tahoma, sans-serif`;
  ctx.textAlign = "left"; ctx.direction = "rtl";
  ctx.fillText("#کشوردوست", pad, h - bandH / 2);
  ctx.restore();

  return canvas;
}

function downloadCanvas(canvas, name, onFail) {
  try {
    canvas.toBlob((blob) => {
      if (!blob) { onFail && onFail(); return; }
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url; a.download = name; a.style.display = "none";
      document.body.appendChild(a); a.click();
      setTimeout(() => { document.body.removeChild(a); URL.revokeObjectURL(url); }, 400);
    }, "image/png");
  } catch (e) {
    // tainted canvas (QR cross-origin) — let caller re-render without it
    onFail && onFail();
  }
}

window.ShareFrame = function ShareFrame({ open, onClose, post }) {
  const [layout, setLayout] = useState("story");
  const [theme,  setTheme]  = useState("neon");
  const [showMeta, setShowMeta] = useState(true);
  const [exporting, setExporting] = useState(null);

  if (!open || !post) return null;

  const L = LAYOUTS.find(l => l.id === layout);
  const T = THEMES.find(t => t.id === theme);

  const network = post.source_type === "external_post" || post.network ? (post.channel?.network || post.network) : null;
  const NET = network ? NETWORK_META[network] : null;

  const userCaption = post.caption || "اثر تازه از کشوردوست — اولین چالشمه که فرستادم!";
  const caption1Line = truncate(userCaption, 60);

  const shareUrl = "keshvardoost.ir/p/" + (post.id || "share");
  const qrSrc = "https://api.qrserver.com/v1/create-qr-code/?size=160x160&margin=0&data="
    + encodeURIComponent("https://" + shareUrl);

  const onExport = (id) => {
    setExporting(id);
    if (id === "download") {
      // preload the QR (CORS-enabled) so it can be drawn into the canvas;
      // fall back to no-QR if it fails so the export never breaks.
      const img = new Image();
      img.crossOrigin = "anonymous";
      const finish = (qrImg) => {
        const c = renderFrameCanvas({ layout, theme, post, showMeta, caption: userCaption, NET, qrImg });
        const fname = `koshvardoost-${post.id || "share"}-${layout}.png`;
        // if drawing the QR tainted the canvas, re-render once without it
        downloadCanvas(c, fname, qrImg ? () => finish(null) : null);
        setTimeout(() => setExporting(null), 600);
      };
      img.onload = () => finish(img);
      img.onerror = () => finish(null);
      img.src = qrSrc;
    } else {
      // network share — would invoke navigator.share or open deep-link
      setTimeout(() => setExporting(null), 1200);
    }
  };

  return (
    <div className="kd-sf" onClick={onClose}>
      <div className="kd-sf__sheet" onClick={e => e.stopPropagation()}>
        <header className="kd-sf__top">
          <h3>قاب کشوردوست</h3>
          <button className="kd-sf__close" onClick={onClose} aria-label="بستن">
            <Icon name="close" size={18} stroke={2} />
          </button>
        </header>

        {/* ---- Live preview ---- */}
        <div className="kd-sf__stage">
          <div
            className={`kd-sf__frame kd-sf__frame--${layout} kd-sf__frame--${theme}`}
            style={{
              ['--frame-bg']: T.bg,
              ['--frame-fg']: T.fg,
              ['--inner-ratio']: L.inner,
              aspectRatio: L.outer,
              width: L.w,
            }}
          >
            {/* Top band */}
            <div className="kd-sf__band kd-sf__band--top">
              <div className="kd-sf__brand">
                <span className="kd-sf__logo">کـ</span>
                <div className="kd-sf__brand-id">
                  <strong>کشوردوست</strong>
                  <span>جشنواره محتوای ایران</span>
                </div>
              </div>
              {NET ? (
                <span className="kd-sf__source" title={`از ${NET.label}`}>
                  <span className="kd-sf__source-glyph" style={{ background: NET.color }}>{NET.glyph}</span>
                  <span className="kd-sf__source-lbl">از {NET.label}</span>
                </span>
              ) : (
                <span className="kd-sf__tag">{post.kind === "video" ? "ویدیو" : post.kind === "image" ? "تصویر" : "اثر"}</span>
              )}
            </div>

            {/* Inner content card — explicit aspect ratio */}
            <div className="kd-sf__inner-wrap">
              <div className="kd-sf__inner">
                <div className="kd-sf__media" style={{ background:
                  `radial-gradient(60% 80% at 25% 25%, rgba(255,78,168,.55), transparent 60%),
                   radial-gradient(60% 80% at 80% 80%, rgba(75,227,255,.45), transparent 60%),
                   linear-gradient(135deg, #1a0a22, #08111e)` }}>
                  {(post.kind === "video" || post.kind === "audio") && (
                    <span className="kd-sf__play">
                      <Icon name="video" size={26} stroke={2.4} />
                    </span>
                  )}
                  {NET && (
                    <span className="kd-sf__media-net" style={{ background: NET.color }} title={NET.label}>{NET.glyph}</span>
                  )}
                </div>
                {showMeta && (
                  <div className="kd-sf__meta">
                    <span className="kd-sf__author">
                      <span className="kd-sf__avatar">{(post.author?.name || "نگار").charAt(0)}</span>
                      <span>
                        <strong>{post.author?.name || "نگار رستمی"}</strong>
                        <em>@{post.author?.handle || "negar.r"}</em>
                      </span>
                    </span>
                    <span className="kd-sf__rate">
                      <Icon name="star" size={11} stroke={0} style={{ fill: "currentColor" }} />
                      {post.rating || 4.7}
                    </span>
                  </div>
                )}
              </div>
            </div>

            {/* Caption — one line, ellipsised */}
            <p className="kd-sf__caption" title={userCaption}>{caption1Line}</p>

            {/* Bottom band — real scannable QR + link */}
            <div className="kd-sf__band kd-sf__band--bottom">
              <img className="kd-sf__qr" src={qrSrc} alt="QR کد اثر" width={46} height={46} loading="lazy" />
              <div className="kd-sf__linkcol">
                <span className="kd-sf__cta">اسکن کن و ببین</span>
                <span className="kd-sf__url">{shareUrl}</span>
              </div>
              <span className="kd-sf__hash">#کشوردوست</span>
            </div>
          </div>
        </div>

        {/* ---- Controls ---- */}
        <section className="kd-sf__controls">
          <header className="kd-sf__crow">
            <span>چیدمان</span>
            <div className="kd-sf__seg">
              {LAYOUTS.map(l => (
                <button key={l.id} className={layout === l.id ? "is-on" : ""} onClick={() => setLayout(l.id)}>{l.label}</button>
              ))}
            </div>
          </header>

          <header className="kd-sf__crow">
            <span>تم</span>
            <div className="kd-sf__themes">
              {THEMES.map(t => (
                <button key={t.id} className={`kd-sf__theme ${theme === t.id ? "is-on" : ""}`} style={{ background: t.bg }} onClick={() => setTheme(t.id)} aria-label={t.label} title={t.label} />
              ))}
            </div>
          </header>

          <header className="kd-sf__crow">
            <span>نشان نویسنده</span>
            <label className="kd-sf__toggle">
              <input type="checkbox" checked={showMeta} onChange={() => setShowMeta(v => !v)} />
              <span />
            </label>
          </header>
        </section>

        {/* ---- Export ---- */}
        <footer className="kd-sf__exports">
          {SHARE_TARGETS.map(t => (
            <button key={t.id} className={`kd-sf__export ${t.id === "download" ? "kd-sf__export--download" : ""}`} onClick={() => onExport(t.id)} disabled={exporting && exporting !== t.id}>
              <span className="kd-sf__export-icon" style={{ background: t.bg }}>
                {exporting === t.id
                  ? <span className="kd-sf__spinner" />
                  : t.id === "download"
                    ? <Icon name="upload" size={20} stroke={2.2} style={{ transform: "rotate(180deg)", color: "#fff" }} />
                    : <span className="kd-sf__export-glyph">{t.glyph}</span>}
              </span>
              <span className="kd-sf__export-lbl">{exporting === t.id ? (t.id === "download" ? "ساختن…" : "ارسال…") : t.label}</span>
            </button>
          ))}
        </footer>

        <p className="kd-sf__note">
          <Icon name="microscope" size={12} stroke={2.2} />
          تصویر روی دستگاهت ساخته می‌شه — هیچ‌چیزی به سرور نمی‌ره مگر اونی که خودت بفرستی.
        </p>
      </div>
    </div>
  );
};
})();
