/* Reusable visual primitives */

// ————————————————————————————————————————————————————————————————
// Hand-drawn Bedouin/folk star — slightly off-symmetric points,
// thicker rough edges, dot at the center (vs. the perfect 8-point geometric).
function Star8({ size = 24, color = "currentColor", className = "", style = {} }) {
  return (
    <svg width={size} height={size} viewBox="0 0 100 100" className={className} style={style}>
      {/* Outer petals — slightly irregular spike lengths and angles */}
      <path
        d="M50 4 L57 38 L94 47 L60 56 L52 96 L42 60 L6 50 L40 41 Z"
        fill={color}
        strokeLinejoin="miter"
      />
      {/* Inner dot ornament — gives it block-print weight */}
      <circle cx="50" cy="50" r="6" fill={color === "currentColor" ? "var(--paper)" : "var(--paper)"} opacity="0.55" />
      <circle cx="50" cy="50" r="2.4" fill={color} />
    </svg>
  );
}

// Geometric arabesque border (SVG pattern strip)
function ArabesqueStrip({ color = "#B8904C", height = 28 }) {
  return (
    <svg width="100%" height={height} viewBox="0 0 400 28" preserveAspectRatio="none" style={{ display: "block" }}>
      <defs>
        <pattern id="ar-pat" width="56" height="28" patternUnits="userSpaceOnUse">
          <path d="M0 14 L14 0 L28 14 L14 28 Z" fill="none" stroke={color} strokeWidth="1" />
          <path d="M28 14 L42 0 L56 14 L42 28 Z" fill="none" stroke={color} strokeWidth="1" />
          <circle cx="14" cy="14" r="2" fill={color} />
          <circle cx="42" cy="14" r="2" fill={color} />
        </pattern>
      </defs>
      <rect width="400" height="28" fill="url(#ar-pat)" />
    </svg>
  );
}

// Seamless Islamic geometric pattern background (subtle)
function GeoPatternBg({ color = "#B8904C", opacity = 0.08 }) {
  return (
    <svg width="100%" height="100%" style={{ position: "absolute", inset: 0, opacity }} preserveAspectRatio="xMidYMid slice">
      <defs>
        <pattern id="geo" width="80" height="80" patternUnits="userSpaceOnUse">
          <g fill="none" stroke={color} strokeWidth="0.8">
            <polygon points="40,6 50,30 74,34 56,52 62,76 40,64 18,76 24,52 6,34 30,30" />
            <circle cx="40" cy="40" r="6" />
            <path d="M0 40 L80 40 M40 0 L40 80" strokeDasharray="2 4" opacity="0.4" />
          </g>
        </pattern>
      </defs>
      <rect width="100%" height="100%" fill="url(#geo)" />
    </svg>
  );
}

// Arch / shape variants — each returns a CSS border-radius string.
// pointed = mosque pointed arch · horseshoe = wider top, gentle return ·
// keel = ogee · square = simple radius · circle = round medallion · scallop = handled separately.
const SHAPE_RADII = {
  arch:      "1000px 1000px 16px 16px / 600px 600px 16px 16px",
  pointed:   "60% 60% 12px 12px / 90% 90% 12px 12px",
  horseshoe: "44% 44% 18px 18px / 70% 70% 18px 18px",
  keel:      "70% 70% 12px 12px / 100% 100% 12px 12px",
  square:    "10px",
  circle:    "50%",
  oval:      "50%",
};

// Placeholder image block with label, supports arch mask
function Placeholder({
  tone = "sand",
  label = "image",
  meta = "—",
  arch = false,
  shape = null,        // optional: 'pointed' | 'horseshoe' | 'keel' | 'square' | 'circle'
  children,
  className = "",
  style = {},
  topLabel = null,
  showAlt = false,     // dim chrome for "real photo" feel
  alt = "",            // accessibility text
  src = null,          // real image overlay; falls back to gradient pattern on load error
  imgFit = "cover",    // "cover" for photos; "contain" for transparent-bg cutouts
  imgPad = 0,          // inset padding (px) for contain cutouts so they breathe
}) {
  const [imgFailed, setImgFailed] = React.useState(false);
  const hasImage = src && !imgFailed;
  const radius = shape ? SHAPE_RADII[shape] : (arch ? SHAPE_RADII.arch : undefined);
  return (
    <div className={`ph ph-${tone} ${arch ? "arch" : ""} ${className}`} style={{
      width: "100%", height: "100%",
      background: tone === "terracotta" ?
        "repeating-linear-gradient(135deg, #A34824 0 2px, transparent 2px 14px), linear-gradient(180deg, #B5502E 0%, #8F3E22 100%)"
      : tone === "olive" ?
        "repeating-linear-gradient(135deg, #252B1E 0 2px, transparent 2px 14px), linear-gradient(180deg, #3E4A35 0%, #2E3528 100%)"
      : tone === "gold" ?
        "repeating-linear-gradient(135deg, #9B7538 0 2px, transparent 2px 14px), linear-gradient(180deg, #C9A56A 0%, #B8904C 100%)"
      : tone === "ink" ?
        "repeating-linear-gradient(135deg, #0D0C09 0 2px, transparent 2px 14px), linear-gradient(180deg, #2B2820 0%, #1C1A15 100%)"
      :
        "repeating-linear-gradient(135deg, #BFAC87 0 2px, transparent 2px 14px), linear-gradient(180deg, #E6D5B3 0%, #C9B894 100%)",
      color: (tone === "terracotta" || tone === "olive" || tone === "ink") ? "#FAF6EE" : "#2E3528",
      borderRadius: radius,
      position: "relative",
      overflow: "hidden",
      ...style
    }}
      // Only expose as an image to assistive tech when an explicit alt is
      // provided; otherwise treat the placeholder as decorative chrome so
      // screen readers don't announce internal slug labels.
      {...(alt ? { role: "img", "aria-label": alt } : { role: "presentation", "aria-hidden": "true" })}
    >
      {hasImage && (
        <img
          src={src}
          alt={alt || ""}
          loading="lazy"
          onError={() => setImgFailed(true)}
          style={{
            position: "absolute", inset: imgPad,
            width: imgPad ? `calc(100% - ${imgPad * 2}px)` : "100%",
            height: imgPad ? `calc(100% - ${imgPad * 2}px)` : "100%",
            objectFit: imgFit, objectPosition: "center",
            display: "block",
            filter: imgFit === "contain"
              ? "drop-shadow(0 18px 26px rgba(28,26,21,0.32))" : undefined,
          }}
        />
      )}
      {topLabel && (
        <div style={{
          position: "absolute", top: 0, left: 0, right: 0, padding: "14px 18px",
          fontFamily: "var(--ff-mono)", fontSize: 10, letterSpacing: "0.2em",
          textTransform: "uppercase", display: "flex", justifyContent: "space-between",
          background: "linear-gradient(180deg, rgba(28,26,21,0.18), transparent)",
        }}>
          <span>{topLabel}</span>
          <span>◆</span>
        </div>
      )}
      {children}
      <div style={{
        position: "absolute", bottom: 0, left: 0, right: 0, padding: "14px 18px",
        fontFamily: "var(--ff-mono)", fontSize: 10, letterSpacing: "0.2em",
        textTransform: "uppercase", display: "flex", justifyContent: "space-between",
        background: "linear-gradient(0deg, rgba(28,26,21,0.22), transparent)",
        pointerEvents: "none",
      }}>
        <span>{label}</span>
        <span>{meta}</span>
      </div>
    </div>
  );
}

// Short bilingual label block
function BiLabel({ en, ar, align = "left" }) {
  return (
    <div style={{ textAlign: align, lineHeight: 1.2 }}>
      <div style={{ fontFamily: "var(--ff-display)", fontStyle: "italic", fontSize: 18, color: "var(--olive)" }}>{en}</div>
      <div className="ar" style={{ fontSize: 16, color: "var(--muted)", marginTop: 2 }}>{ar}</div>
    </div>
  );
}

// Wordmark — SANAA with Arabic companion
function Wordmark({ size = 28, color = "var(--ink)" }) {
  return (
    <div className="wordmark" style={{ display: "flex", alignItems: "baseline", gap: 10, color, whiteSpace: "nowrap" }}>
      <span style={{
        fontFamily: "var(--ff-display)",
        fontSize: size,
        letterSpacing: "0.18em",
        fontWeight: 500,
      }}>SANAA</span>
      <span className="ar wordmark-ar" style={{
        fontSize: size * 0.78,
        color: "var(--terracotta)",
      }}>صَنعة</span>
    </div>
  );
}

function ArabicCalligraphyBg({ color = "currentColor" }) {
  // Dense abstract Arabic calligraphy pattern — interwoven letterforms
  // inspired by Hassan Massoudy / Rabia-style compositions.
  // Tile is 260×260, repeated.
  return (
    <svg width="100%" height="100%" preserveAspectRatio="xMidYMid slice" xmlns="http://www.w3.org/2000/svg">
      <defs>
        <pattern id="calligraphy-tile" x="0" y="0" width="260" height="260" patternUnits="userSpaceOnUse">
          <g fill="none" stroke={color} strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round">
            {/* --- Row 1: sweeping letter-like strokes --- */}
            {/* large 'ص'-like bowl */}
            <path d="M10 38 C 20 18, 58 18, 62 40 C 64 56, 40 60, 34 50" />
            {/* vertical 'ا' cluster */}
            <path d="M72 12 L 72 52" />
            <path d="M80 8 L 80 48" />
            {/* 'ن'-like curve with dot */}
            <path d="M94 30 C 100 50, 130 52, 138 34" />
            <circle cx="116" cy="18" r="3" fill={color} stroke="none" />
            {/* long horizontal stroke */}
            <path d="M150 42 C 170 42, 180 30, 200 32 C 218 34, 230 46, 250 40" />
            {/* ending loop 'و'-like */}
            <path d="M244 22 C 254 22, 258 32, 250 36 C 244 38, 240 32, 244 28 Z" />

            {/* --- Row 2 --- */}
            <path d="M6 88 C 26 70, 46 92, 34 104 C 24 114, 10 108, 14 96" />
            {/* 'ح'-like deep bowl */}
            <path d="M48 82 C 52 110, 90 114, 94 90 C 96 78, 78 74, 72 84" />
            {/* dual 'ي' dots */}
            <circle cx="64" cy="118" r="2.4" fill={color} stroke="none" />
            <circle cx="72" cy="118" r="2.4" fill={color} stroke="none" />
            {/* long sweep like 'ل' */}
            <path d="M110 62 C 114 98, 148 110, 160 94 C 168 84, 158 74, 150 82" />
            {/* 'ك'-like angular */}
            <path d="M172 70 L 186 72 L 184 90 L 200 92" />
            <path d="M176 78 L 184 80" />
            {/* 'ه' closed form */}
            <path d="M210 84 C 208 70, 236 68, 238 84 C 240 98, 214 102, 210 90 Z" />

            {/* --- Row 3: descenders & tails --- */}
            {/* 'ج'-like hook with dot */}
            <path d="M14 138 C 20 160, 52 164, 60 146 C 64 136, 48 130, 42 138" />
            <circle cx="36" cy="168" r="2.8" fill={color} stroke="none" />
            {/* 'س'-like triple teeth */}
            <path d="M78 148 L 84 140 L 90 148 L 96 140 L 102 148 L 116 148 C 124 148, 128 158, 120 162" />
            {/* 'ر'-like descender */}
            <path d="M130 138 C 140 150, 138 170, 126 174" />
            {/* 'ط'-like with vertical */}
            <path d="M150 134 L 150 166 L 184 166 C 196 166, 196 150, 184 150 L 154 150" />
            {/* 'م'-like round head */}
            <path d="M204 148 C 198 138, 218 130, 224 140 C 230 150, 220 158, 214 156 L 214 178" />
            {/* diamond accents */}
            <path d="M236 156 L 240 160 L 236 164 L 232 160 Z" fill={color} />

            {/* --- Row 4 --- */}
            <path d="M10 210 C 30 192, 48 218, 40 228" />
            {/* 'ع'-like coil */}
            <path d="M58 204 C 48 214, 62 226, 72 218 C 80 212, 76 198, 64 200 C 58 202, 60 208, 64 208" />
            {/* wavy 'ش' with three dots */}
            <path d="M92 218 L 98 210 L 104 218 L 110 210 L 116 218 L 130 218 C 138 218, 142 228, 134 232" />
            <circle cx="100" cy="200" r="1.8" fill={color} stroke="none" />
            <circle cx="106" cy="196" r="1.8" fill={color} stroke="none" />
            <circle cx="112" cy="200" r="1.8" fill={color} stroke="none" />
            {/* 'ف'-like with top dot */}
            <path d="M148 212 C 152 200, 176 200, 180 212 C 182 224, 170 228, 164 222" />
            <circle cx="164" cy="196" r="2.4" fill={color} stroke="none" />
            {/* 'ق'-like with two dots + descender */}
            <path d="M196 212 C 198 200, 224 200, 226 212 C 228 224, 220 232, 208 238" />
            <circle cx="208" cy="196" r="2" fill={color} stroke="none" />
            <circle cx="216" cy="196" r="2" fill={color} stroke="none" />
            {/* end flourish */}
            <path d="M240 214 C 250 214, 258 222, 254 232" />

            {/* --- fillers & connectors --- */}
            <path d="M2 252 C 30 240, 70 254, 110 246 C 150 240, 190 252, 230 244 C 248 240, 256 244, 260 250" opacity="0.7" />
            <path d="M38 176 C 60 180, 88 180, 108 176" opacity="0.5" />
            <path d="M142 112 C 158 116, 176 116, 192 112" opacity="0.5" />
            {/* small diamonds scattered */}
            <path d="M6 70 L 10 74 L 6 78 L 2 74 Z" fill={color} />
            <path d="M254 112 L 258 116 L 254 120 L 250 116 Z" fill={color} />
            <path d="M126 252 L 130 256 L 126 260 L 122 256 Z" fill={color} />
          </g>
        </pattern>
      </defs>
      <rect width="100%" height="100%" fill="url(#calligraphy-tile)" />
    </svg>
  );
}

function DiagonalLinesBg({ color = "currentColor", spacing = 14, strokeWidth = 1.2, angle = 45 }) {
  // simple diagonal line pattern — tiled with CSS-like approach in SVG
  const tile = spacing;
  return (
    <svg width="100%" height="100%" preserveAspectRatio="xMidYMid slice" xmlns="http://www.w3.org/2000/svg">
      <defs>
        <pattern id={`diag-${spacing}-${angle}`} x="0" y="0" width={tile} height={tile} patternUnits="userSpaceOnUse" patternTransform={`rotate(${angle})`}>
          <line x1="0" y1="0" x2="0" y2={tile} stroke={color} strokeWidth={strokeWidth} />
        </pattern>
      </defs>
      <rect width="100%" height="100%" fill={`url(#diag-${spacing}-${angle})`} />
    </svg>
  );
}

// Shamsiya — 16-point sun rosette (Mamluk window) — for headers & seals
function Shamsiya({ size = 80, color = "currentColor", strokeWidth = 1, fill = "none" }) {
  const rays = [];
  for (let i = 0; i < 16; i++) {
    const a = (i * Math.PI * 2) / 16;
    const x1 = 50 + Math.cos(a) * 18;
    const y1 = 50 + Math.sin(a) * 18;
    const x2 = 50 + Math.cos(a) * 46;
    const y2 = 50 + Math.sin(a) * 46;
    rays.push(<line key={i} x1={x1} y1={y1} x2={x2} y2={y2} stroke={color} strokeWidth={strokeWidth} />);
  }
  // 8-petal interior
  const pts = [];
  for (let i = 0; i < 16; i++) {
    const a = (i * Math.PI * 2) / 16;
    const r = i % 2 === 0 ? 22 : 12;
    pts.push(`${50 + Math.cos(a) * r},${50 + Math.sin(a) * r}`);
  }
  return (
    <svg width={size} height={size} viewBox="0 0 100 100" style={{ display: "block" }}>
      <circle cx="50" cy="50" r="46" fill={fill} stroke={color} strokeWidth={strokeWidth} />
      <circle cx="50" cy="50" r="22" fill={fill} stroke={color} strokeWidth={strokeWidth} />
      <polygon points={pts.join(" ")} fill={fill} stroke={color} strokeWidth={strokeWidth} />
      {rays}
      <circle cx="50" cy="50" r="3" fill={color} />
    </svg>
  );
}

// QR placeholder — generated grid that *looks* like a QR (12x12 deterministic pattern)
function QrMark({ size = 96, color = "currentColor", bg = "transparent", seed = "sanaa" }) {
  // deterministic pseudo-random
  let h = 0; for (let i = 0; i < seed.length; i++) h = (h * 31 + seed.charCodeAt(i)) | 0;
  const rng = () => { h = (h * 1664525 + 1013904223) | 0; return ((h >>> 0) % 1000) / 1000; };
  const N = 12, cell = 100 / N;
  const cells = [];
  for (let y = 0; y < N; y++) {
    for (let x = 0; x < N; x++) {
      // mirror left/right for QR-like symmetry-ish
      const xx = x < N / 2 ? x : N - 1 - x;
      const k = (xx * 31 + y * 17) ^ ((seed.charCodeAt((x + y) % seed.length) || 0) * 7);
      const on = (Math.abs(Math.sin(k + (rng() * 0.0001))) > 0.55);
      if (on) cells.push(<rect key={x + "-" + y} x={x * cell} y={y * cell} width={cell} height={cell} fill={color} />);
    }
  }
  // three position markers (corners)
  const marker = (cx, cy) => (
    <g key={cx + "-" + cy}>
      <rect x={cx} y={cy} width={cell * 3} height={cell * 3} fill={color} />
      <rect x={cx + cell * 0.5} y={cy + cell * 0.5} width={cell * 2} height={cell * 2} fill={bg === "transparent" ? "var(--paper)" : bg} />
      <rect x={cx + cell} y={cy + cell} width={cell} height={cell} fill={color} />
    </g>
  );
  return (
    <svg width={size} height={size} viewBox="0 0 100 100" style={{ display: "block", background: bg }}>
      {cells}
      {marker(0, 0)}
      {marker(100 - cell * 3, 0)}
      {marker(0, 100 - cell * 3)}
    </svg>
  );
}

// Wax-seal style mark — circular emblem with star + edition number
function WaxSeal({ size = 80, edition = "№ 017", color = "var(--terracotta)" }) {
  return (
    <div style={{
      width: size, height: size, borderRadius: "50%",
      background: `radial-gradient(circle at 35% 35%, ${color === "var(--terracotta)" ? "#C56A48" : color}, ${color === "var(--terracotta)" ? "#7E351E" : color})`,
      color: "var(--paper)", display: "grid", placeItems: "center",
      position: "relative",
      boxShadow: `inset 0 -4px 8px rgba(28,26,21,0.3), 0 6px 16px -6px rgba(28,26,21,0.5)`,
      fontFamily: "var(--ff-mono)", fontSize: size * 0.12, letterSpacing: "0.18em",
      textTransform: "uppercase",
    }}>
      <div style={{ textAlign: "center", lineHeight: 1.1 }}>
        <Star8 size={size * 0.24} color="var(--paper)" />
        <div style={{ marginTop: size * 0.04, opacity: 0.92 }}>{edition}</div>
      </div>
    </div>
  );
}

// Audio waveform — purely decorative; rendered as bars for "play maker voice"
function Waveform({ bars = 28, color = "currentColor", height = 28, playing = false }) {
  const seed = bars * 7;
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 2, height }}>
      {Array.from({ length: bars }).map((_, i) => {
        const h = 30 + Math.abs(Math.sin(i * 0.6 + seed)) * 70;
        return (
          <div key={i} style={{
            width: 2, height: `${h}%`, background: color, borderRadius: 2,
            opacity: playing ? 0.9 : 0.55,
            transformOrigin: "center",
            animation: playing ? `waveBar 0.8s ease-in-out ${i * 0.05}s infinite alternate` : "none",
          }} />
        );
      })}
      <style>{`@keyframes waveBar { to { transform: scaleY(0.45); } }`}</style>
    </div>
  );
}

// Folk icon set — drawn in the spirit of Tunis-village pottery glyphs
// and Sinai Bedouin tattoo motifs. Block-print fills, slightly irregular
// strokes, dotted ornament — nothing geometrically perfect.
//
// Visual DNA:
//   • two-dot or three-dot ornament beside the main shape
//   • mixed fill + stroke (not pure outline)
//   • palmette / fan / crescent / oasis vocabulary
//   • thicker hand-cut lines (1.6–2.0)
//   • warm strokeLinecap "round"
function Icon({ name, size = 22, color = "currentColor", strokeWidth = 1.6 }) {
  const p = { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth, strokeLinecap: "round", strokeLinejoin: "round" };
  const f = { ...p, fill: color };
  // tiny dot ornament
  const dots = (cx, cy, n = 2, r = 0.7) => Array.from({ length: n }, (_, i) => (
    <circle key={i} cx={cx + i * 2.4} cy={cy} r={r} fill={color} stroke="none" />
  ));

  switch (name) {
    // SUN — desert sun: filled disk with hand-cut rays + two dots
    case "sun": return (
      <svg {...p}>
        <circle cx="12" cy="12" r="3.4" fill={color} stroke="none" />
        <path d="M12 2.5v2.4M12 19.1v2.4M2.5 12h2.4M19.1 12h2.4M5.2 5.2l1.7 1.7M17.1 17.1l1.7 1.7M5.2 18.8l1.7-1.7M17.1 6.9l1.7-1.7" />
        <circle cx="12" cy="12" r="6.4" strokeDasharray="0.4 2.2" />
      </svg>
    );

    // DROP — water-jar drop with a notch (qulla glyph)
    case "drop": return (
      <svg {...p}>
        <path d="M12 3.2c-2.6 4.4-5.4 7.4-5.4 11.2a5.4 5.4 0 0 0 10.8 0c0-3.8-2.8-6.8-5.4-11.2Z" fill={color} fillOpacity="0.18" />
        <path d="M12 3.2c-2.6 4.4-5.4 7.4-5.4 11.2a5.4 5.4 0 0 0 10.8 0c0-3.8-2.8-6.8-5.4-11.2Z" />
        <path d="M9.4 13.6c.6 1.4 2 2 3.2 1.6" />
      </svg>
    );

    // NO-WATER — drop crossed with bedouin-style x
    case "no-water": return (
      <svg {...p}>
        <path d="M12 3.2c-2.6 4.4-5.4 7.4-5.4 11.2a5.4 5.4 0 0 0 10.8 0c0-3.8-2.8-6.8-5.4-11.2Z" />
        <path d="M4.4 4.4l15.2 15.2M19.6 4.4L4.4 19.6" />
      </svg>
    );

    // HAND — khamsa (hand of fatima): palm + thumb, dot in center
    case "hand": return (
      <svg {...p}>
        <path d="M7.2 13.6c0-2.6 0-5 .4-7.4.2-1.2 1.6-1.4 1.8-.2.2 1.6.2 3.2.2 4.8" />
        <path d="M9.6 10.8V4.4c0-1.4 1.8-1.4 1.8 0v6.4" />
        <path d="M11.4 10.8V5.2c0-1.4 1.8-1.4 1.8 0v5.6" />
        <path d="M13.2 10.8V6.6c0-1.4 1.8-1.4 1.8 0v4.6" />
        <path d="M15 11.4c0-1.4 2-1.4 2 .2v4.4c0 3.4-2.6 6-6 6-3.4 0-5.2-1.8-6-4.6-.4-1.4-1-2.8-1.8-3.8-.8-1 .4-2.2 1.4-1.6l1.6 1.2" />
        <circle cx="12" cy="15.6" r="1.4" fill={color} stroke="none" />
        <circle cx="12" cy="15.6" r="0.5" fill="var(--paper)" stroke="none" />
      </svg>
    );

    // LEAF — palm frond (sa'af) with central spine and side blades
    case "leaf": return (
      <svg {...p}>
        <path d="M4 20.4c0-8.4 7.6-15.6 16-15.6.4 0 .4.4 0 .8C12 13.6 6.6 19.4 4 20.4Z" fill={color} fillOpacity="0.16" />
        <path d="M4 20.4c0-8.4 7.6-15.6 16-15.6.4 0 .4.4 0 .8C12 13.6 6.6 19.4 4 20.4Z" />
        <path d="M5.4 19l9.4-9.4" />
        <path d="M7 17.4l1.6-3M9 15.4l2.4-2M11.6 12.8l3-1.4M14.6 9.8l3.4-1" />
      </svg>
    );

    // FIRE — kiln flame, three tongues
    case "fire": return (
      <svg {...p}>
        <path d="M12 2.6c-.6 3 1 4 1 6.4 0 1.4-1.2 2-1.8 1-.6-.8-.4-2-.4-2-1.6 1-3.4 3-3.4 5.6a6.6 6.6 0 0 0 13.2 0c0-3.4-2.4-5.6-3.4-7.2C16 4.6 14.4 3.4 12 2.6Z" fill={color} fillOpacity="0.22" />
        <path d="M12 2.6c-.6 3 1 4 1 6.4 0 1.4-1.2 2-1.8 1-.6-.8-.4-2-.4-2-1.6 1-3.4 3-3.4 5.6a6.6 6.6 0 0 0 13.2 0c0-3.4-2.4-5.6-3.4-7.2C16 4.6 14.4 3.4 12 2.6Z" />
        <path d="M12 13.6c-.4 1 .6 1.6 1.4 1" />
      </svg>
    );

    // FEATHER — Ma'at feather (Egyptian symbol of truth/balance)
    case "feather": return (
      <svg {...p}>
        <path d="M12 2.4c-3.4 2.6-5.4 6-5.4 10.4 0 3 .6 6 2 8.8 1-.4 5-1.4 6.6-3.6 1.8-2.4 2.6-5.4 2.6-8.6 0-3-.6-5.6-1.6-7-.8-1.2-2.4-1.2-4.2 0Z" fill={color} fillOpacity="0.15" />
        <path d="M12 2.4c-3.4 2.6-5.4 6-5.4 10.4 0 3 .6 6 2 8.8 1-.4 5-1.4 6.6-3.6 1.8-2.4 2.6-5.4 2.6-8.6 0-3-.6-5.6-1.6-7-.8-1.2-2.4-1.2-4.2 0Z" />
        <path d="M11 4.4v18M9.4 8.4l3.2 1.6M9.2 12l3.4 1.4M9 15.6l3.6 1.4" />
      </svg>
    );

    // WAX — wax-seal disc with star imprint
    case "wax": return (
      <svg {...p}>
        <circle cx="12" cy="13" r="6.4" fill={color} fillOpacity="0.18" />
        <circle cx="12" cy="13" r="6.4" />
        <path d="M12 9.4l1.2 2.4 2.4.4-1.8 1.6.4 2.6-2.2-1.4-2.2 1.4.4-2.6-1.8-1.6 2.4-.4Z" fill={color} stroke="none" />
        <path d="M9.6 7l4.8-3.4M9.6 4.4l4.8 3" />
      </svg>
    );

    // BOX — woven crate / qaffa basket with weave lines
    case "box": return (
      <svg {...p}>
        <path d="M3.4 7.2L12 3.4l8.6 3.8L12 11Z" fill={color} fillOpacity="0.2" />
        <path d="M3.4 7.2L12 3.4l8.6 3.8L12 11ZM3.4 7.2v10L12 21l8.6-3.8v-10M12 11v10" />
        <path d="M5.6 9.4l3.6 1.4M14.8 10.8l3.6-1.4M7 13l1.4 6M16 13l-1.4 6" strokeWidth="0.9" />
      </svg>
    );

    // TRUCK — replaced with CAMEL silhouette (carrying baskets)
    case "truck": return (
      <svg {...p}>
        <path d="M2.4 17c0-1.4 1-2.4 1.6-3 .2-2 .8-4 2.4-4 1 0 1.6.8 2 1.6h3.4c.4-.8 1-1.6 2-1.6 1.4 0 2 1.2 2.2 2.4l3 1.4c1.2.6 2 1.6 2 2.6v1.4M5 17.4v2M19 17.4v2" fill={color} fillOpacity="0.15" />
        <path d="M2.4 17c0-1.4 1-2.4 1.6-3 .2-2 .8-4 2.4-4 1 0 1.6.8 2 1.6h3.4c.4-.8 1-1.6 2-1.6 1.4 0 2 1.2 2.2 2.4l3 1.4c1.2.6 2 1.6 2 2.6v1.4M5 17.4v2M19 17.4v2" />
        <path d="M7 8.4c0-.8.6-1.4 1.4-1.4M7.6 7.6V5.4" />
      </svg>
    );

    // PLAY — palmette-style triangle with dot
    case "play": return (
      <svg {...f}>
        <polygon points="6.6 4.4 19.4 12 6.6 19.6" />
        <circle cx="3.6" cy="12" r="0.9" />
      </svg>
    );

    // PAUSE — two upright wedges (like minarets)
    case "pause": return (
      <svg {...p}>
        <path d="M7.4 4.4l-.6 15.2M9.6 4.4l.6 15.2" fill={color} stroke={color} strokeWidth="2.4" />
        <path d="M14.4 4.4l-.6 15.2M16.6 4.4l.6 15.2" stroke={color} strokeWidth="2.4" />
      </svg>
    );

    // SEARCH — eye (Eye of Horus simplified, no extras)
    case "search": return (
      <svg {...p}>
        <path d="M2.4 12c2.4-3.6 5.6-5.4 9.6-5.4s7.2 1.8 9.6 5.4c-2.4 3.6-5.6 5.4-9.6 5.4S4.8 15.6 2.4 12Z" fill={color} fillOpacity="0.12" />
        <path d="M2.4 12c2.4-3.6 5.6-5.4 9.6-5.4s7.2 1.8 9.6 5.4c-2.4 3.6-5.6 5.4-9.6 5.4S4.8 15.6 2.4 12Z" />
        <circle cx="12" cy="12" r="2.4" fill={color} stroke="none" />
        <path d="M21.4 14.6l1.4 2M14.4 17l.6 1.6" strokeWidth="1.2" />
      </svg>
    );

    // GIFT — wrapped bundle (sorra) with knot on top
    case "gift": return (
      <svg {...p}>
        <path d="M3.6 9.4h16.8v11H3.6Z" fill={color} fillOpacity="0.15" />
        <path d="M3.6 9.4h16.8v11H3.6ZM3.6 13.4h16.8M12 9.4v11" />
        <path d="M9 9c-2 0-2.4-3.6 0-3.6 1.6 0 2.6 2.6 3 3.6M15 9c2 0 2.4-3.6 0-3.6-1.6 0-2.6 2.6-3 3.6" />
        <circle cx="12" cy="5.4" r="0.8" fill={color} stroke="none" />
      </svg>
    );

    // PIN — palm tree on a hill (oasis marker)
    case "pin": return (
      <svg {...p}>
        <path d="M12 22c-2-2-4.4-4.4-4.4-7" />
        <path d="M12 22c2-2 4.4-4.4 4.4-7" />
        <path d="M12 14V6" strokeWidth="2" />
        <path d="M12 6c-2-1.6-4-1.4-4 .4M12 6c2-1.6 4-1.4 4 .4M12 6c-1.4-2.2-3.4-2.6-4.4-1.6M12 6c1.4-2.2 3.4-2.6 4.4-1.6M12 6c-.6-2.6-2-3.6-3.6-3.4M12 6c.6-2.6 2-3.6 3.6-3.4" />
        <circle cx="12" cy="6" r="1" fill={color} stroke="none" />
      </svg>
    );

    // LOCK — keyhole shaped like a teardrop, with two dots
    case "lock": return (
      <svg {...p}>
        <rect x="4.6" y="11" width="14.8" height="10.4" rx="1.4" fill={color} fillOpacity="0.15" />
        <rect x="4.6" y="11" width="14.8" height="10.4" rx="1.4" />
        <path d="M7.6 11V7.4a4.4 4.4 0 0 1 8.8 0V11" />
        <circle cx="12" cy="15.4" r="1.4" fill={color} stroke="none" />
        <path d="M12 16.4v2.4" strokeWidth="2" />
      </svg>
    );

    // CHECK — block-print check, slightly off-axis
    case "check": return (
      <svg {...p}>
        <path d="M3.6 12.4l5.6 6L20.6 5.4" strokeWidth="2.4" />
        <circle cx="22" cy="3.6" r="0.8" fill={color} stroke="none" />
      </svg>
    );

    // THERMO — kiln thermometer with notches
    case "thermo": return (
      <svg {...p}>
        <path d="M14 14.4V4.4a2 2 0 1 0-4 0v10a4 4 0 1 0 4 0Z" fill={color} fillOpacity="0.18" />
        <path d="M14 14.4V4.4a2 2 0 1 0-4 0v10a4 4 0 1 0 4 0Z" />
        <circle cx="12" cy="17.4" r="1.6" fill={color} stroke="none" />
        <path d="M14.4 6.4h1.4M14.4 9h1.4M14.4 11.6h1.4" strokeWidth="1.1" />
      </svg>
    );

    // CALENDAR — moon-phase strip (Hijri-feel)
    case "calendar": return (
      <svg {...p}>
        <rect x="3" y="5.4" width="18" height="15.6" rx="1.4" fill={color} fillOpacity="0.12" />
        <rect x="3" y="5.4" width="18" height="15.6" rx="1.4" />
        <path d="M3 10.4h18" />
        <path d="M8 3v4.4M16 3v4.4" strokeWidth="2" />
        <circle cx="7.4" cy="14.4" r="1.4" />
        <path d="M11.4 14.4a1.4 1.4 0 1 0 0 2.8" fill={color} stroke="none" />
        <circle cx="15.4" cy="14.4" r="1.4" fill={color} stroke="none" />
        <circle cx="19" cy="14.4" r="0.8" fill={color} stroke="none" />
      </svg>
    );

    // SCISSORS — shears with handle dots
    case "scissors": return (
      <svg {...p}>
        <circle cx="6.4" cy="6.4" r="2.6" />
        <circle cx="6.4" cy="17.6" r="2.6" />
        <path d="M9 8.6l11.4 11.4M9 15.4L20.4 4" />
        <circle cx="6.4" cy="6.4" r="0.7" fill={color} stroke="none" />
        <circle cx="6.4" cy="17.6" r="0.7" fill={color} stroke="none" />
      </svg>
    );

    // MOON — crescent (hilal) with star
    case "moon": return (
      <svg {...p}>
        <path d="M20.6 14.4a8 8 0 1 1-9.4-10.4 6.4 6.4 0 0 0 9.4 10.4Z" fill={color} fillOpacity="0.18" />
        <path d="M20.6 14.4a8 8 0 1 1-9.4-10.4 6.4 6.4 0 0 0 9.4 10.4Z" />
        <path d="M16.4 6.4l.6 1.4 1.6.2-1.2 1 .4 1.6-1.4-.8-1.4.8.4-1.6-1.2-1 1.6-.2Z" fill={color} stroke="none" />
      </svg>
    );

    // —— additional folk icons (new) ——

    // EYE-OF-HORUS — for "view / details"
    case "eye": return (
      <svg {...p}>
        <path d="M2 12c4-5 14-5 18 0M2 12c4 5 14 5 18 0" />
        <circle cx="11.6" cy="12" r="2.4" fill={color} stroke="none" />
        <path d="M19 13c1.4 1 1.6 2.6 1 4M14 14.4c.4 2.4-.6 3.6-2 4.4" strokeWidth="1.2" />
      </svg>
    );

    // BASKET — qaffa (palm-fibre basket, account icon replacement)
    case "basket": return (
      <svg {...p}>
        <path d="M4.4 9.4h15.2L17.6 20H6.4Z" fill={color} fillOpacity="0.18" />
        <path d="M4.4 9.4h15.2L17.6 20H6.4Z" />
        <path d="M3 9.4h18" strokeWidth="2" />
        <path d="M8 5c1-2 7-2 8 0" />
        <path d="M9 11.4l-.6 6.6M12 11.4v6.6M15 11.4l.6 6.6" strokeWidth="0.9" />
      </svg>
    );

    // STAR — eight-point star (najma)
    case "star": return (
      <svg {...p}>
        <path d="M12 2.4l1.4 4.6 4.6 1.4-4.6 1.4-1.4 4.6-1.4-4.6-4.6-1.4 4.6-1.4Z" fill={color} fillOpacity="0.2" />
        <path d="M12 2.4l1.4 4.6 4.6 1.4-4.6 1.4-1.4 4.6-1.4-4.6-4.6-1.4 4.6-1.4Z" />
        <path d="M12 21l-2-2.4 2-1 2 1Z" fill={color} stroke="none" />
      </svg>
    );

    // CAMEL — for shipping
    case "camel": return (
      <svg {...p}>
        <path d="M3 17c0-1.4.6-2 1.4-2.4.4-1.8 1.4-3.4 2.6-3.6.2-1.6.6-3.4 1.6-3.4 1 0 1.4 1.4 1.4 2.8h4c.2-.8.8-1.6 1.8-1.6 1.6 0 2 1.4 2.4 3 1.6.4 2.4 1.4 2.6 3.4l.6 1.4M5.4 17.4l-.4 2.4M19 17.4l.6 2.4" />
        <circle cx="6.4" cy="14" r="0.7" fill={color} stroke="none" />
        <path d="M8.4 6.4c-.4-.6-.4-1.4 0-1.8" />
      </svg>
    );

    // PALM — single date palm (small, for footer / oasis chips)
    case "palm": return (
      <svg {...p}>
        <path d="M12 22V8" strokeWidth="2" />
        <path d="M12 8c-3-2-6-1-7 1.4M12 8c3-2 6-1 7 1.4M12 8c-1.4-3-4-4-6.4-3M12 8c1.4-3 4-4 6.4-3M12 8c-.4-3.4-2.4-4.4-4.4-4M12 8c.4-3.4 2.4-4.4 4.4-4" />
        <circle cx="12" cy="8" r="1.2" fill={color} stroke="none" />
        <path d="M11 12l-.4 2M13 14l.4 2M11 16l-.4 2" strokeWidth="0.8" />
      </svg>
    );

    // OASIS — date palm + water dot (for shipping/pickup origin)
    case "oasis": return (
      <svg {...p}>
        <path d="M9 22V12" strokeWidth="1.6" />
        <path d="M9 12c-3-1.4-5-1-6 1M9 12c3-1.4 5-1 6 1M9 12c-1-2.4-3.4-3.4-5.4-2.6M9 12c1.4-2.6 4-3.4 5.6-2.6M9 12c.4-2.6-1-4-3-4.4M9 12c-.4-2.6 1.4-4 3.4-4" />
        <circle cx="9" cy="12" r="1" fill={color} stroke="none" />
        <path d="M14 18.4c0-1.4 1.4-3 1.4-4.4M15.4 14a1.6 1.6 0 1 0 0 3.2 1.6 1.6 0 0 0 0-3.2Z" fill={color} fillOpacity="0.5" stroke="none" />
        <path d="M3 22h18" strokeDasharray="0.4 1.6" />
      </svg>
    );

    // KNOT — bedouin braid knot (for "close / cancel")
    case "knot": return (
      <svg {...p}>
        <path d="M5 5c4 4 10 10 14 14M19 5c-4 4-10 10-14 14" strokeWidth="2" />
        <circle cx="12" cy="12" r="2" fill={color} stroke="none" />
        <circle cx="12" cy="12" r="0.7" fill="var(--paper)" stroke="none" />
        <circle cx="3.4" cy="12" r="0.6" fill={color} stroke="none" />
        <circle cx="20.6" cy="12" r="0.6" fill={color} stroke="none" />
      </svg>
    );

    // ARROW-RIGHT — hand-drawn arrow (folk, slightly waving)
    case "arrow": return (
      <svg {...p}>
        <path d="M3 12.4c4 .4 8 .2 17-.4" strokeWidth="2" />
        <path d="M16 7l4 5-4 5" strokeWidth="2" />
        <circle cx="3" cy="12.4" r="0.8" fill={color} stroke="none" />
      </svg>
    );

    // CUP — coffee/karkade cup (for hospitality / tea section)
    case "cup": return (
      <svg {...p}>
        <path d="M5 9h12l-1 7c-.2 2-2 3-4 3h-2c-2 0-3.8-1-4-3Z" fill={color} fillOpacity="0.18" />
        <path d="M5 9h12l-1 7c-.2 2-2 3-4 3h-2c-2 0-3.8-1-4-3Z" />
        <path d="M17 11c2 0 3 1 3 3s-1 3-3 3" />
        <path d="M9 6c-.4-1 .4-1.6.4-2.6M12 6c-.4-1 .4-1.6.4-2.6M15 6c-.4-1 .4-1.6.4-2.6" strokeWidth="1.1" />
      </svg>
    );

    default: return null;
  }
}

// Editorial section break — Egyptian/Arabic proverb with translation,
// flanked by shamsiyat. Use sparingly between major sections.
function ProverbBreak({ ar, en, attribution = null, tone = "paper" }) {
  return (
    <section style={{
      padding: "80px 0", background: tone === "ink" ? "var(--ink)" : "var(--paper)",
      color: tone === "ink" ? "var(--paper)" : "var(--ink)",
      borderTop: "1px solid var(--line-2)", borderBottom: "1px solid var(--line-2)",
    }}>
      <div className="container" style={{ maxWidth: 880, textAlign: "center" }}>
        <div style={{ display: "flex", justifyContent: "center", gap: 28, marginBottom: 26, opacity: 0.5 }}>
          <Shamsiya size={28} color="currentColor" strokeWidth={0.8} />
          <Star8 size={14} color="currentColor" />
          <Shamsiya size={28} color="currentColor" strokeWidth={0.8} />
        </div>
        <div className="ar" dir="rtl" style={{
          fontFamily: "'Amiri', serif", fontSize: "clamp(28px, 3.5vw, 44px)",
          lineHeight: 1.55, color: tone === "ink" ? "var(--gold-soft)" : "var(--terracotta)",
          marginBottom: 18,
        }}>
          « {ar} »
        </div>
        <div dir="ltr" style={{
          fontFamily: "var(--ff-display)", fontStyle: "italic",
          fontSize: "clamp(20px, 2.2vw, 30px)", lineHeight: 1.4,
          color: tone === "ink" ? "rgba(244,237,226,0.78)" : "var(--olive)",
          maxWidth: 640, margin: "0 auto",
        }}>
          “{en}”
        </div>
        {attribution && (
          <div style={{
            marginTop: 22, fontFamily: "var(--ff-mono)", fontSize: 10,
            letterSpacing: "0.24em", textTransform: "uppercase",
            color: tone === "ink" ? "rgba(244,237,226,0.5)" : "var(--muted)",
          }}>— {attribution}</div>
        )}
      </div>
    </section>
  );
}

// ════════════════════════════════════════════════════════════════════════
//  BRAND FORM CONTROLS
//  Shared, reusable, bilingual + RTL-correct replacements for native form
//  controls (select, date/datetime, file) and alert(). Other UI files import
//  these off `window` — see the API doc returned with this change.
//  Styles live in styles.css §20. Everything is logical-property driven so it
//  mirrors automatically in RTL; pass `dir`/`lang` for text + chevron mirror.
// ════════════════════════════════════════════════════════════════════════

// Small inline chevron used by BrandSelect (kept local so primitives has no
// hard dependency on a specific Icon glyph for this control).
function BfChevron({ size = 14 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none"
      stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <path d="M6 9l6 6 6-6" />
    </svg>
  );
}
function BfCalendar({ size = 18 }) {
  // reuse the folk calendar glyph for brand consistency
  return <Icon name="calendar" size={size} color="currentColor" />;
}

// ── window.BrandSelect ──────────────────────────────────────────────────
// A fully custom dropdown (button + listbox) so the OPTION LIST is brand
// styled too. Keyboard accessible (↑/↓/Home/End/Enter/Esc/type-ahead),
// focus-visible terracotta ring, paper surface, RTL-correct.
//
// Props:
//   value       — currently selected option value (string|number)
//   onChange    — (value) => void   ·  receives the raw option `value`
//   options     — [{ value, label, disabled? }]
//   placeholder — shown when no value selected (string)
//   lang        — "en" | "ar"   (defaults to <html lang> if omitted)
//   dir         — "ltr" | "rtl" (defaults from lang)
//   disabled    — boolean
//   ariaLabel   — accessible name for the trigger (string)
//   id, name    — optional pass-throughs
function BrandSelect({
  value, onChange, options = [], placeholder,
  lang, dir, disabled = false, ariaLabel, id, name, style,
}) {
  const _lang = lang || (typeof document !== "undefined" ? document.documentElement.lang : "en") || "en";
  const _dir = dir || (_lang === "ar" ? "rtl" : "ltr");
  const ph = placeholder != null ? placeholder : (_lang === "ar" ? "اختر…" : "Select…");

  const [open, setOpen] = React.useState(false);
  const [active, setActive] = React.useState(-1); // keyboard-highlighted index
  const [up, setUp] = React.useState(false);
  const rootRef = React.useRef(null);
  const triggerRef = React.useRef(null);
  const listRef = React.useRef(null);
  const typeahead = React.useRef({ str: "", t: 0 });

  const selectedIdx = options.findIndex(o => String(o.value) === String(value));
  const selectedLabel = selectedIdx >= 0 ? options[selectedIdx].label : null;

  // Close on outside click / Esc
  React.useEffect(() => {
    if (!open) return;
    const onDoc = (e) => { if (rootRef.current && !rootRef.current.contains(e.target)) setOpen(false); };
    document.addEventListener("mousedown", onDoc);
    return () => document.removeEventListener("mousedown", onDoc);
  }, [open]);

  // Decide open direction + seed the active row when opening
  const openList = () => {
    if (disabled) return;
    const r = triggerRef.current && triggerRef.current.getBoundingClientRect();
    if (r) setUp((window.innerHeight - r.bottom) < 240 && r.top > 240);
    setActive(selectedIdx >= 0 ? selectedIdx : firstEnabled());
    setOpen(true);
  };
  const firstEnabled = () => options.findIndex(o => !o.disabled);
  const lastEnabled = () => { for (let i = options.length - 1; i >= 0; i--) if (!options[i].disabled) return i; return -1; };
  const nextEnabled = (from, step) => {
    let i = from;
    for (let n = 0; n < options.length; n++) {
      i = (i + step + options.length) % options.length;
      if (!options[i].disabled) return i;
    }
    return from;
  };

  const choose = (idx) => {
    const o = options[idx];
    if (!o || o.disabled) return;
    onChange && onChange(o.value);
    setOpen(false);
    triggerRef.current && triggerRef.current.focus();
  };

  // keep active row scrolled into view
  React.useEffect(() => {
    if (!open || active < 0 || !listRef.current) return;
    const el = listRef.current.children[active];
    if (el && el.scrollIntoView) el.scrollIntoView({ block: "nearest" });
  }, [active, open]);

  const onKeyDown = (e) => {
    if (disabled) return;
    if (!open) {
      if (["ArrowDown", "ArrowUp", "Enter", " "].includes(e.key)) { e.preventDefault(); openList(); }
      return;
    }
    switch (e.key) {
      case "Escape": e.preventDefault(); setOpen(false); triggerRef.current && triggerRef.current.focus(); break;
      case "ArrowDown": e.preventDefault(); setActive(a => nextEnabled(a < 0 ? -1 : a, 1)); break;
      case "ArrowUp": e.preventDefault(); setActive(a => nextEnabled(a < 0 ? 0 : a, -1)); break;
      case "Home": e.preventDefault(); setActive(firstEnabled()); break;
      case "End": e.preventDefault(); setActive(lastEnabled()); break;
      case "Enter": case " ": e.preventDefault(); choose(active); break;
      case "Tab": setOpen(false); break;
      default:
        // type-ahead
        if (e.key.length === 1) {
          const now = Date.now();
          typeahead.current.str = (now - typeahead.current.t < 700 ? typeahead.current.str : "") + e.key.toLowerCase();
          typeahead.current.t = now;
          const hit = options.findIndex(o => !o.disabled && String(o.label).toLowerCase().startsWith(typeahead.current.str));
          if (hit >= 0) setActive(hit);
        }
    }
  };

  const listId = (id || name || "bsel") + "-list";
  return (
    <div className="bsel" ref={rootRef} data-open={open ? "true" : "false"} dir={_dir} style={style}>
      <button
        type="button" ref={triggerRef} id={id} name={name}
        className="bf-field bsel-trigger brand-focus"
        role="combobox" aria-haspopup="listbox" aria-expanded={open}
        aria-controls={open ? listId : undefined}
        aria-label={ariaLabel} aria-disabled={disabled || undefined}
        disabled={disabled}
        onClick={() => (open ? setOpen(false) : openList())}
        onKeyDown={onKeyDown}
      >
        <span className={"bsel-value" + (selectedLabel == null ? " bf-placeholder" : "")}>
          {selectedLabel != null ? selectedLabel : ph}
        </span>
        <span className="bf-affix bsel-chevron"><BfChevron /></span>
      </button>

      {open && (
        <ul className="bsel-pop" ref={listRef} id={listId} role="listbox"
          aria-label={ariaLabel} tabIndex={-1}>
          {options.length === 0 && (
            <li className="bsel-opt bf-placeholder" aria-disabled="true">
              {_lang === "ar" ? "لا خيارات" : "No options"}
            </li>
          )}
          {options.map((o, i) => {
            const isSel = String(o.value) === String(value);
            return (
              <li key={String(o.value) + i}
                className="bsel-opt"
                role="option"
                aria-selected={isSel}
                aria-disabled={o.disabled || undefined}
                data-active={i === active ? "true" : "false"}
                onMouseEnter={() => !o.disabled && setActive(i)}
                onMouseDown={(e) => { e.preventDefault(); choose(i); }}
              >
                <span>{o.label}</span>
                <span className="bsel-tick" aria-hidden="true"><Icon name="check" size={14} color="currentColor" /></span>
              </li>
            );
          })}
        </ul>
      )}
    </div>
  );
}

// ── window.BrandDate / window.BrandDateTime ─────────────────────────────
// A brand-styled, locale-aware date (or datetime) control that NEVER shows a
// raw mm/dd/yyyy. A real <input type=date|datetime-local> is layered
// transparently on top (so the native picker + keyboard still work) while a
// localized formatted value renders beneath via fmtDate/fmtDateTime.
//
// Props:
//   value       — "" | "yyyy-mm-dd"           (date)
//                 "" | "yyyy-mm-ddThh:mm"      (datetime, withTime)
//   onChange    — (value) => void  · emits the SAME format above (or "" when cleared)
//   withTime    — boolean → datetime-local instead of date
//   lang, dir   — locale + direction (default from <html>)
//   min, max    — native bounds, same format as value
//   placeholder — empty-state text (defaults bilingual)
//   ariaLabel   — accessible name
//   disabled    — boolean
//   id, name    — pass-throughs
function BrandDate({
  value, onChange, withTime = false,
  lang, dir, min, max, placeholder, ariaLabel, disabled = false,
  id, name, style,
}) {
  const _lang = lang || (typeof document !== "undefined" ? document.documentElement.lang : "en") || "en";
  const _dir = dir || (_lang === "ar" ? "rtl" : "ltr");
  const ph = placeholder != null ? placeholder
    : (_lang === "ar" ? (withTime ? "اختر التاريخ والوقت" : "اختر تاريخًا")
                      : (withTime ? "Pick date & time" : "Pick a date"));

  // The native <input> needs a parseable value. date → yyyy-mm-dd as-is;
  // datetime-local → yyyy-mm-ddThh:mm as-is. We pass value through unchanged.
  const nativeType = withTime ? "datetime-local" : "date";

  // Localized display. For datetime we feed an ISO-ish string to fmtDateTime;
  // datetime-local has no zone so we treat it as local wall-clock.
  let display = null;
  if (value) {
    display = withTime
      ? (window.fmtDateTime
          ? window.fmtDateTime(value, _lang, { day: "numeric", month: "long", year: "numeric", hour: "2-digit", minute: "2-digit" })
          : value)
      : (window.fmtDate
          ? window.fmtDate(value, _lang, { day: "numeric", month: "long", year: "numeric" })
          : value);
  }

  return (
    <div className="bdate" dir={_dir} style={style}>
      <input
        type={nativeType}
        className="bdate-native"
        id={id} name={name}
        value={value || ""}
        min={min} max={max}
        disabled={disabled}
        aria-label={ariaLabel || ph}
        onChange={(e) => onChange && onChange(e.target.value)}
      />
      <div className="bf-field bdate-display" aria-hidden="true">
        <span className={display == null ? "bf-placeholder" : ""}>
          {display != null ? display : ph}
        </span>
        <span className="bf-affix"><BfCalendar size={18} /></span>
      </div>
    </div>
  );
}
function BrandDateTime(props) { return <BrandDate {...props} withTime={true} />; }

// ── window.BrandFileDrop / window.BrandFileInput ────────────────────────
// A styled upload affordance: dashed paper dropzone + bilingual label +
// custom button, wrapping a hidden <input type=file>. Drag-and-drop aware,
// shows selected filenames, RTL-correct.
//
// IMPORTANT: this component only surfaces the chosen File objects via
// `onFiles`. It does NOT upload. Callers keep their own storage-path /
// getPublicUrl logic — never store full URLs.
//
// Props:
//   onFiles     — (FileList-as-Array) => void  · the chosen File[]
//   accept      — input accept string (e.g. "image/jpeg,image/png")
//   multiple    — boolean
//   lang, dir   — locale + direction (default from <html>)
//   label       — primary line override (string); defaults bilingual
//   hint        — secondary line (e.g. "JPEG · PNG — up to 8 MB")
//   disabled    — boolean
//   showList    — show the selected-file list (default true)
//   ariaLabel   — accessible name for the hidden input
//   id, name    — pass-throughs
function BrandFileDrop({
  onFiles, accept, multiple = false,
  lang, dir, label, hint, disabled = false, showList = true,
  ariaLabel, id, name, style,
}) {
  const _lang = lang || (typeof document !== "undefined" ? document.documentElement.lang : "en") || "en";
  const _dir = dir || (_lang === "ar" ? "rtl" : "ltr");
  const inputRef = React.useRef(null);
  const [drag, setDrag] = React.useState(false);
  const [files, setFiles] = React.useState([]);

  const primary = label != null ? label
    : (_lang === "ar"
        ? (multiple ? "اسحب الصور هنا، أو اختر من جهازك" : "اسحب الصورة هنا، أو اختر من جهازك")
        : (multiple ? "Drag images here, or choose from your device" : "Drag an image here, or choose from your device"));
  const cta = _lang === "ar" ? "اختر ملفًا" : "Choose file";

  const fmtSize = (b) => {
    if (b < 1024) return b + " B";
    if (b < 1024 * 1024) return (b / 1024).toFixed(0) + " KB";
    return (b / 1024 / 1024).toFixed(1) + " MB";
  };

  const emit = (list) => {
    const arr = Array.from(list || []);
    setFiles(arr);
    onFiles && onFiles(arr);
  };
  const onInput = (e) => emit(e.target.files);
  const onDrop = (e) => {
    e.preventDefault(); setDrag(false);
    if (disabled) return;
    emit(e.dataTransfer.files);
  };
  const openPicker = () => { if (!disabled && inputRef.current) inputRef.current.click(); };
  const removeAt = (i) => {
    const next = files.filter((_, j) => j !== i);
    setFiles(next);
    onFiles && onFiles(next);
    if (inputRef.current) inputRef.current.value = "";
  };

  return (
    <div className="bfile" dir={_dir} style={style}>
      <input
        ref={inputRef} type="file" accept={accept} multiple={multiple}
        id={id} name={name} disabled={disabled}
        onChange={onInput}
        aria-label={ariaLabel || primary}
        style={{ position: "absolute", width: 1, height: 1, opacity: 0, pointerEvents: "none" }}
        data-testid={name ? "upload-" + name : undefined}
      />
      <div
        className="bfile-zone brand-focus"
        role="button" tabIndex={disabled ? -1 : 0}
        aria-disabled={disabled || undefined}
        data-drag={drag ? "true" : "false"}
        onClick={openPicker}
        onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); openPicker(); } }}
        onDragOver={(e) => { e.preventDefault(); if (!disabled) setDrag(true); }}
        onDragLeave={() => setDrag(false)}
        onDrop={onDrop}
      >
        <span className="bfile-icon"><Icon name="box" size={30} color="currentColor" /></span>
        <span className="bfile-label">{primary}</span>
        {hint && <span className="bfile-hint">{hint}</span>}
        <span className="bfile-cta">{cta} +</span>
      </div>
      {showList && files.length > 0 && (
        <ul className="bfile-list">
          {files.map((f, i) => (
            <li key={f.name + i} className="bfile-file">
              <span className="bfile-name">{f.name}</span>
              <span className="bfile-size">{fmtSize(f.size)}</span>
              <button type="button" className="bfile-remove"
                aria-label={_lang === "ar" ? "إزالة" : "Remove"}
                onClick={(e) => { e.stopPropagation(); removeAt(i); }}>
                <Icon name="knot" size={14} color="currentColor" />
              </button>
            </li>
          ))}
        </ul>
      )}
    </div>
  );
}

// ── window.toast(message, { type, lang, duration }) ─────────────────────
// Minimal, brand-styled, RTL-aware, auto-dismiss toast. Imperative API so it
// can replace alert() anywhere (inside or outside React). Stacks; each toast
// auto-dismisses. Returns a dismiss() function.
//   type     — "info" (default) | "success" | "error"
//   lang     — "en" | "ar" (only affects font/dir of the toast; default <html>)
//   duration — ms before auto-dismiss (default 3600; 0 = sticky)
const toast = (function () {
  let host = null;
  const ensureHost = () => {
    if (host && document.body.contains(host)) return host;
    host = document.createElement("div");
    host.className = "bf-toast-host";
    host.setAttribute("role", "status");
    host.setAttribute("aria-live", "polite");
    document.body.appendChild(host);
    return host;
  };
  return function toast(message, opts = {}) {
    const { type = "info", lang, duration = 3600 } = opts;
    const _lang = lang || (typeof document !== "undefined" ? document.documentElement.lang : "en") || "en";
    const _dir = _lang === "ar" ? "rtl" : "ltr";
    const h = ensureHost();
    const el = document.createElement("div");
    el.className = "bf-toast " + (type || "info") + (_lang === "ar" ? " ar" : "");
    el.setAttribute("dir", _dir);
    const iconName = type === "success" ? "check" : type === "error" ? "knot" : "star";
    el.innerHTML =
      '<span class="bf-toast-icon"></span>' +
      '<span class="bf-toast-text"></span>';
    // render the folk icon as inline SVG via a tiny React-free draw
    el.querySelector(".bf-toast-text").textContent = message == null ? "" : String(message);
    // simple SVG glyphs (avoid pulling React render into an imperative API)
    const glyphs = {
      check: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M3.6 12.4l5.6 6L20.6 5.4"/></svg>',
      knot: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 5l14 14M19 5L5 19"/></svg>',
      star: '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M12 3l1.6 5.4L19 10l-5.4 1.6L12 17l-1.6-5.4L5 10l5.4-1.6z"/></svg>',
    };
    el.querySelector(".bf-toast-icon").innerHTML = glyphs[iconName] || glyphs.star;
    h.appendChild(el);

    let done = false;
    const dismiss = () => {
      if (done) return; done = true;
      el.classList.add("out");
      el.addEventListener("animationend", () => { if (el.parentNode) el.parentNode.removeChild(el); }, { once: true });
      // safety removal in case animationend doesn't fire
      setTimeout(() => { if (el.parentNode) el.parentNode.removeChild(el); }, 400);
    };
    el.addEventListener("click", dismiss);
    if (duration > 0) setTimeout(dismiss, duration);
    return dismiss;
  };
})();

Object.assign(window, {
  Star8, ArabesqueStrip, GeoPatternBg, ArabicCalligraphyBg, DiagonalLinesBg,
  Placeholder, BiLabel, Wordmark, Shamsiya, QrMark, WaxSeal, Waveform, Icon,
  ProverbBreak, IconGalleryPage,
  BrandSelect, BrandDate, BrandDateTime, BrandFileDrop, BrandFileInput: BrandFileDrop, toast,
});

// Folk-icon gallery page — for review at #/icons
function IconGalleryPage({ lang = "en" }) {
  const groups = [
    { h: "Care & material", ar: "العناية والخامات", icons: [
      { n: "sun", l: "Sun-dry", a: "تجفّفه الشمس" },
      { n: "moon", l: "Hand-wash cool", a: "غسيل بارد" },
      { n: "drop", l: "Damp cloth", a: "قماشة مبلولة" },
      { n: "no-water", l: "No water", a: "بدون ماء" },
      { n: "fire", l: "Kiln-fired", a: "محروق بفرن" },
      { n: "thermo", l: "Heat 1180°", a: "حرارة" },
      { n: "leaf", l: "Plant fibre", a: "ألياف نباتية" },
      { n: "feather", l: "Light/airy", a: "خفيف" },
    ]},
    { h: "Process & make", ar: "الصُنع", icons: [
      { n: "hand", l: "Khamsa", a: "خمسة" },
      { n: "wax", l: "Wax-sealed", a: "ختم شمعي" },
      { n: "scissors", l: "Trimmed", a: "مقصوص" },
      { n: "calendar", l: "Made over weeks", a: "أسابيع" },
      { n: "check", l: "Verified", a: "موثّق" },
      { n: "lock", l: "Reserved", a: "محجوز" },
    ]},
    { h: "Place & journey", ar: "المكان والرحلة", icons: [
      { n: "pin", l: "Atelier mark", a: "موقع المحترف" },
      { n: "palm", l: "Palm tree", a: "نخلة" },
      { n: "oasis", l: "Oasis origin", a: "واحة" },
      { n: "camel", l: "Slow ship", a: "شحن بطيء" },
      { n: "box", l: "Qaffa box", a: "قَفّة" },
      { n: "basket", l: "Basket", a: "سلة" },
    ]},
    { h: "Action & UI", ar: "الواجهة", icons: [
      { n: "search", l: "Look", a: "بحث" },
      { n: "eye", l: "View detail", a: "مشاهدة" },
      { n: "play", l: "Play film", a: "تشغيل" },
      { n: "pause", l: "Pause", a: "إيقاف" },
      { n: "arrow", l: "Continue", a: "تابع" },
      { n: "knot", l: "Close (knot)", a: "إغلاق" },
      { n: "gift", l: "Gift wrap", a: "هديّة" },
      { n: "star", l: "Featured", a: "مميّزة" },
      { n: "cup", l: "Hospitality", a: "ضيافة" },
    ]},
  ];
  return (
    <>
      <section style={{ padding: "70px 0 50px", background: "var(--paper)", borderBottom: "1px solid var(--line-2)" }}>
        <div className="container-wide">
          <div className="eyebrow"><span className="dot"></span>{lang === "en" ? "Folk icon set · v0.1" : "الأيقونات الشعبية · ٠٫١"}</div>
          <h1 style={{ fontFamily: "var(--ff-display)", fontSize: "clamp(56px, 6vw, 88px)", marginTop: 18, letterSpacing: "-0.02em", lineHeight: 1 }}>
            {lang === "en" ? <>Drawn by hand,<br /><em style={{ color: "var(--terracotta)" }}>not by software.</em></> : <>مرسومة باليد، <em style={{ color: "var(--terracotta)" }}>لا ببرنامج.</em></>}
          </h1>
          <p style={{ marginTop: 22, fontSize: 17, color: "var(--olive)", maxWidth: 640, lineHeight: 1.7 }}>
            {lang === "en" ? "Tunis-village pottery glyphs and Sinai Bedouin tattoo motifs — adapted for a marketplace, kept rough on purpose. No off-the-shelf icon kits." : "نقوش فخار قرية تونس ووشم بدو سيناء — مُعدَّلة لسوقٍ رقمي، محتفظة بخشونتها."}
          </p>
        </div>
      </section>
      <section style={{ padding: "60px 0 120px", background: "var(--paper-2)" }}>
        <div className="container-wide" style={{ display: "grid", gap: 60 }}>
          {groups.map((g, gi) => (
            <div key={gi}>
              <div style={{ display: "flex", alignItems: "baseline", gap: 18, marginBottom: 28, paddingBottom: 14, borderBottom: "1px solid var(--line-2)" }}>
                <h2 style={{ fontFamily: "var(--ff-display)", fontSize: 36, letterSpacing: "-0.01em" }}>{lang === "en" ? g.h : g.ar}</h2>
                <span style={{ fontFamily: "var(--ff-mono)", fontSize: 11, letterSpacing: "0.22em", color: "var(--muted)" }}>({g.icons.length})</span>
              </div>
              <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 18 }}>
                {g.icons.map((ic, i) => (
                  <div key={i} style={{ background: "var(--paper)", border: "1px solid var(--line-2)", borderRadius: 12, padding: "28px 22px", display: "grid", gridTemplateColumns: "auto 1fr", gap: 22, alignItems: "center" }}>
                    <div style={{ width: 64, height: 64, borderRadius: 10, background: "var(--paper-2)", display: "grid", placeItems: "center", color: "var(--terracotta)" }}>
                      <Icon name={ic.n} size={36} />
                    </div>
                    <div>
                      <div style={{ fontFamily: "var(--ff-display)", fontSize: 18, lineHeight: 1.2 }}>{lang === "en" ? ic.l : ic.a}</div>
                      <div style={{ fontFamily: "var(--ff-mono)", fontSize: 10, letterSpacing: "0.2em", textTransform: "uppercase", color: "var(--muted)", marginTop: 6 }}>{ic.n}</div>
                    </div>
                  </div>
                ))}
              </div>
            </div>
          ))}

          {/* Scale & color test */}
          <div>
            <div style={{ marginBottom: 28, paddingBottom: 14, borderBottom: "1px solid var(--line-2)" }}>
              <h2 style={{ fontFamily: "var(--ff-display)", fontSize: 36, letterSpacing: "-0.01em" }}>{lang === "en" ? "At every size & on every surface" : "بكل حجم وعلى كل خلفية"}</h2>
            </div>
            <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 24 }}>
              {[
                { bg: "var(--paper)", c: "var(--ink)", l: "Paper / ink" },
                { bg: "var(--ink)", c: "var(--gold-soft)", l: "Ink / gold" },
                { bg: "var(--terracotta)", c: "var(--paper)", l: "Terracotta / paper" },
                { bg: "var(--paper-2)", c: "var(--olive)", l: "Sand / olive" },
              ].map((t, i) => (
                <div key={i} style={{ background: t.bg, color: t.c, padding: "30px 28px", borderRadius: 14, border: "1px solid var(--line-2)" }}>
                  <div style={{ fontFamily: "var(--ff-mono)", fontSize: 10, letterSpacing: "0.2em", textTransform: "uppercase", marginBottom: 18, opacity: 0.7 }}>{t.l}</div>
                  <div style={{ display: "flex", gap: 26, alignItems: "center", flexWrap: "wrap" }}>
                    {["sun", "hand", "palm", "camel", "star", "wax", "eye", "moon"].map(n => (
                      <Icon key={n} name={n} size={28} />
                    ))}
                  </div>
                  <div style={{ display: "flex", gap: 20, alignItems: "flex-end", marginTop: 24 }}>
                    {[16, 22, 32, 48, 64].map(s => <Icon key={s} name="palm" size={s} />)}
                  </div>
                </div>
              ))}
            </div>
          </div>
        </div>
      </section>
    </>
  );
}
